TweetFollow Us on Twitter

Resource Templates

Volume Number: 14 (1998)
Issue Number: 9
Column Tag: Tools Of The Trade

Resource Templates

by Doug McKenna, Mathemæsthetics, Inc
Edited by the MacTech Editorial Staff

Programming on the Macintosh involves creating and managing a variety of complicated data structures that describe everything from a basic window to the preferences data structure of our specific applications. As Macintosh programmers we rely on resource editors, like Apple's ResEdit and Mathemæsthetics Resorcerer to view and manipulate many of those data structures. In turn, those resource editors rely on TMPL type resources to define and record the structure of all other types of resources. In this article, Doug McKenna (the author of the high performance resource editor Resorcerer) presents an introduction to TMPL resources. - The Editor

What is a Resource Template?

Resorcerer contains a powerful 32-bit data editor that parses blocks of data of a given resource type into the data's constituent editable fields. It does this by following a set of instructions that declares the sequential format of the data. Each set of instructions is called a template, and each template is itself kept in a resource of type 'TMPL'. The binary data format of the template resource is quite simple, and can itself be described by another 'TMPL'. Editing templates, however, is such a common and important activity that there is a dedicated editor within Resorcerer designed specifically for dealing with 'TMPL' resources.

Each 'TMPL' resource has the same internal structure for its own data, but the data itself describes different data formats. The first four characters of the 'TMPL' resource's name, when taken as a resource type, uniquely identify the resource type that the template decribes. Resorcerer pays attention to templates it finds installed in any of several folders next to the application which are reserved for keeping common or private templates; or in resource files that it has opened for editing; or within Resorcerer's own application resources (Figure 1). 'TMPL' resources whose names are less than 4 ASCII characters in length are ignored. 'TMPL' resource IDs are also ignored.

Figure 1. Template Resources in a File.

The data within each template is nothing more than an arbitrarily long list of data parsing instructions, also called fields. Each field consists of two parts: (1) a variable-length Pascal-style string, followed by (2) a four-byte parsing code. Instructions are packed one after the other; there are no pad or alignment bytes anywhere. There is also no initial count, so that the number of instructions in the template can only be determined by parsing the thing until the end of the template data is reached (Figure 2).

Figure 2. TMPL Structure.

The string is called the instruction's label, and, being Pascal, consists of an unsigned length byte, followed by that many bytes of character data. The label primarily serves to identify for the user of the Data Editor the meaning of each parsed data field. Occasionally, the label has certain special characteristics for the benefit of the Data Editor's parser/formatter/interface (for instance, if the label is "Reserved", "Filler", or "Unused", the editor doesn't allow the user to edit the field), but in general the label is equivalent to a comment in a compiled language, and can be set to whatever you like. For instance, in the Japanese version of Resorcerer, the field labels are translated into Kanji.

The four-byte parsing code is called the field's type. It usually encodes both the size and manner of presentation of the next data field to be parsed sequentially from the data; however, there are a variety of special purpose codes that guide Resorcerer's parser in higher-level ways, or which are used to enhance the interactive interface of the Data Editor.

Resorcerer is Upwardly Compatible with ResEdit Templates

Other types of template resources have been designed, notably for MacsBug ('mxwt' resources) and Metrowerks' Constructor ('CTYP' resources), both of which can in turn be described by Resorcerer templates. The descriptive capabilities of Rez templates, which are kept in source code text files rather than resources, are more powerful, but can only be used for compiling.

The simple and elegant 'TMPL' structure described above was first implemented in Apple's resource editor, ResEdit, over a dozen years ago. Although you can edit a minimal set of simple Macintosh resources with ResEdit templates, in the ensuing years Apple and its developers have created much larger and more complicated data structures, which ResEdit cannot support. This is due primarily to reliance on compiling resources with Rez, but also from using the enhanced features that Resorcerer has provided over the years.

ResEdit supports 36 template field parsing codes; Resorcerer supports 128 (or more, if you count a handful of synonym field types implemented for mnemonic consistency). Fortunately, though, 34 of those 128 operate exactly the same as far as properly parsing data built with ResEdit, and the remaining 2 types (Booleans and fixed-length Pascal string buffers) are configurable to behave compatibly or not. Thus if you've invested time in creating your own ResEdit templates and built resources with them, Resorcerer's Data Editor can use your templates unchanged, and you can still edit the resources you or others have previously created.

Differences Among Data Descriptions

To see the differences among various ways of describing a well known resource, consider the different ways that the dialog window ('DLOG') resource can be described using Rez, ResEdit, Resorcerer, and C. The data format is simple enough: a few consecutive numeric fields, followed by a Pascal string for the window title, followed by another numeric field.

Listing 1: Four ways to describe a 'DLOG'

Rez Template
type 'DLOG' {
   integer      documentProc, dBoxProc, plainDBox, altDBoxProc,
                noGrowDocProc, movableDBoxProc, zoomDocProc = 8,
                zoomNoGrow = 12, rDocProc = 16;
   byte           invisible, visible;
   fill byte;
   byte               noGoAway, goAway;
   fill byte;
   unsigned hex longint;   
   pstring    Untitled = "Untitled";
#if SystemSevenOrLater
   align word;
   unsigned integer   noAutoCenter = 0x0000,
                      centerMainScreen = 0x280a,
                      alertPositionMainScreen = 0x300a,
                      staggerMainScreen = 0x380a,
                      centerParentWindow = 0xa80a,
                      alertPositionParentWindow = 0xb00a,
                      staggerParentWindow = 0xb80a,
                      centerParentWindowScreen = 0x680a,
                      alertPositionParentWindowScreen = 0x700a,
                      staggerParentWindowScreen = 0x780a;

ResEdit TMPL
   RECT            BoundsRect
   DWRD            ProcID
   BOOL            Visible
   BOOL            GoAway
   DLNG            RefCon
   DWRD            Items ID
   PSTR            Title
   HWRD            Auto Position

Resorcerer TMPL
   RECT            BoundsRect
   WB12            'WDEF' resource ID
      CASE         Standard system=0
      CASE         Standard desk accessory=1
   WB04            Variation code
      CASE         Document/standard accessory=0
      CASE         Modal dialog=1
      CASE         Plain frame=2
      CASE         Shadow frame=3
      CASE         Non-growable document=4
      CASE         Moveable modal dialog=5
      CASE         Zoomable document=8
      CASE         No grow, zoomable document=12
   BOOL            Visible
   BOOL            GoAway
   DLNG            RefCon
   RSID            Item list ('DITL') resource ID
   ESTR            Title
   HWRD            Window placement
      CASE         Leave it alone=$0000
      CASE         Center on main screen=$280A
      CASE         Center in parent window=$A80A
      CASE         Center on parent's screen=$680A
      CASE         Alert on main screen=$300A
      CASE         Alert in parent window=$B00A
      CASE         Alert in parent's screen=$700A
      CASE         Stagger on main screen=$380A
      CASE         Stagger in parent window=$B80A
      CASE         Stagger on parent's screen=$780A

C struct
#pragma options align=mac68k
typedef struct {
   Rect            boundsRect;            
   short           procID;
   char            visible;      
   char            filler1;
   char            goAwayFlag;            
   char            filler2;
   long            refCon;      
   Str255          title;
   short           positionCode;            
} WINDResource;
#pragam options align=reset

Note that the C struct is not an accurate description of the resource data format, because the size of the title in the resource data is variable, whereas in the above a fixed-length Str255 buffer of maximum size of 256 bytes has been declared. Because of this, you can't cast the resource data handle to (WINDResource **) and expect the positionCode field to have the correct value in it.

Also worth noting is that both the Resorcerer and Rez descriptions include symbolic definitions of various field constants of interest directly in the format declaration; whereas the ResEdit and C descriptions don't.

The Rez definition of a 'DLOG' actually defines two data structures, depending on whether the constant SystemSevenOrLater is defined to be 1 or not.

Creating a New Template

To create a new template in Resorcerer, launch the resource editor, choose New File (CMD-N) and then choose New Resource (CMD-N) to specify the 'TMPL'. The resource ID can be anything; you can set the resource name to any four-character type you want the template to describe (for instance, 'test'). This brings up Resorcerer's Template Editor, which initally displays nothing since there are no fields defined yet in your new template. You can then choose New Field (CMD-N) from the editor's Template menu (or double-click on the field insertion caret's triangle) and enter the field data parsing type code and its label string. The field window provides you with a complete listing of all possible 4-character field types and their meanings, in case you're not sure what the four-character code is.

The Template Editor in Resorcerer displays and edits 'TMPL' resources (Figure 3); the Data Editor then uses the template to parse your resource as a data structure declared by the template (Figure 4). When a resource is selected in Resorcerer's File Window, and the Data button is enabled, this means that a template for that resource type is available for the Data Editor to use.

Figure 3. Editing a TMPL Field.

Figure 4. The Data Editor uses a TMPL to edit an 'ldes' resource.

Once you're familiar with the various template field types and operation, it is usually easier to type the list of field types and labels into a text file and then copy and paste them all at once into the Template Editor's window. You can do the reverse also: select any set of fields, choose Copy, and you can paste the template fields into a text file (Figure 5).

Figure 5. Editing a TMPL as text.

Resorcerer Template Field Types

The template field types that Resorcerer supports can parse and format many categories of data. The newer types were defined over the years as needed, based on what developers, including myself, were doing in various resource data structures, or for ease-of-use interface reasons in the Data Editor's operation, or for consistency. Since each "opcode" is allowed only 4 characters, it has been somewhat of a struggle to ensure some form of consistency in the type mnemonics. For instance, in general, an initial 'B' stands for "byte", a 'W' stands for a 2-byte "word" (left-over from 68k terminology, not PPC terminology), and 'L' stands for a 4-byte long. 'H' stands for hex, 'U' for unsigned, 'D' for signed decimal, 'P' for Pascal, and 'C' for C (how succinct!). 'S' stands for some form of Sized. In the context of delimiting groups of fields, the suffix 'B' stands for "begin" and 'E' stands for "end". I have studiously avoided using any lower-case characters, as this would add a whole degree of freedom to the difficulty of remembering what code is what.

In the following headings, the Resorcerer-specific extensions to the original ResEdit types are in boldface, and I've added some anecdotes explaining how some of these newer types came about.

Bits, bit fields, and boolean flags


The BBIT, WBIT, and LBIT fields each parse one bit out of the current byte, 2-byte word, or 4-byte long. Bits are parsed from most significant to least significant. Each of these is the same as a boolean field in a Rez template, but when Resorcerer's Data Editor displays the data, it numbers the bits appropriately depending on the field type: 7 to 0 for BBITs, 15 to 0 for WBITs, and 31 to 0 for LBITs. The bit-numbering is reversed if little-ending parsing mode is in effect.

The BBnn, WBnn, and LBnn fields operate similarly, except that instead of parsing just 1 bit, they each parse the next nn bits, where nn is a 2-digit ASCII decimal number encoded directly into the field type (sort of an immediate argument for the parsing opcode). Thus, WB01 is the same as WBIT; LB14 parses 14 bits from within a 32-bit long; etc. Each of these is the same as a boolean[] array in Rez.

You can intermix the single-bit with multi-bit parsing fields in series, as long as the total number of bits always exactly reaches a byte, word, or long boundary, depending on whether you are using the 'B...', 'W...', or 'L...' variant. The Data Editor performs no implicit hidden padding in any way, and will complain if a multi-byte field crosses an appropriate storage boundary. For example, the two declarations

Listing 2: Declarations

Bits declared in C
unsigned long sizeCode : 2,
                   localChannel : 4,
                   isExtinct : 1,
                   isPurple : 1,
                   isDinosaur : 1,
                   isObnoxious : 1,
                   groupCount : 21;

Bits in Resorcerer TMPL
      LB02         Size code
      LB04         Local channel
      LBIT         Is extinct?
      LBIT         Is a dinosaur?
      LBIT         Is purple?
      LBIT         Is obnoxious?
      LB21         Number of newsgroups
      LBIT         Filler

are basically the same, with the exception that in C the missing low-order bit is silently added by the compiler, whereas in a TMPL, you have to explicitly declare everything: the total number of consecutive 'WB' bits has to add up to a multiple of 16.

I originally implemented the various word and long extensions to the BBIT field type because documentation for various bit flags routinely refers to them by bit number (e.g. bit 24 in this long field), and I couldn't stand sitting in front of multi-thousand dollar computing machine, forced to count bits in order to get things just right.

The BFLG, WFLG, and LFLG fields are designed to correspond to how a single boolean flag has historically been coded in C, which is to say, as the value 0 or 1 stored in the low-order bit of a byte, short, or long integer. The higher order bits are parsed automatically by these three field types, but those bits are not editable and are set to 0. For instance, BFLG is the same as [BB07, BBIT].

The BOOL field actually parses 2 bytes. The value of the field is TRUE if it exactly matches the 16-bit value kept in Resorcerer's own 'BOOL' 128 resource, which is set to 0x0100. The BOOL field type was implemented originally in ResEdit to take care of the hidden padding problem that occurs in C structs and Pascal records. Boolean fields are typed to be single bytes, but because of this, the 68k compilers would add a hidden pad byte after the Boolean field. So a BOOL field is TRUE if its integer value is 256, and FALSE if it's 0. I was never able to find any documentation on its behavior. After watching what ResEdit did, I chose to make the operation configurable with a 'BOOL' resource, since I wasn't sure what it was supposed to do. You should try to avoid using this field type in favor of the more explicit bit types above.

Decimal and hexadecimal integers, and resource IDs


These instructions simply parse 8-bit, 16-bit, and 32-bit integer fields, depending on whether the field ends in 'BYT', 'WRD', or 'LNG'. The 'D' variants display and edit the data as signed decimal numbers; the 'U' variants as unsigned decimal; and the 'H' variants as unsigned hex. Parsing is subject to the current endian mode.

Since storing the resource ID of some related resource as a 2-byte integer is very common, Resorcerer has a special RSID field just for this purpose, allowing you to edit the related resource easily. The RSID field parses a 2-byte signed short integer, and displays it the same as a DWRD. But since the special field lets Resorcerer's Data Editor know that the number is really a resource ID, the editor can let you quickly interactively link to (i.e. open with an editor) the referenced resource in the same file. To do this, though, it needs to figure out what the resource type is, which it does in one of two ways. For instance, if your template field sequence contains the instructions

Listing 3: Resource References

Resource references in a template
RSID Resource ID of new icon suite ('icns')

TNAM Type of icon suite
RSID Resource ID of icon suite

then the Data Editor will be able to figure out which resource to open or create when you ask it to edit the referenced resource. With the first RSID field, the resource type to use is hardwired into the field's label ('icns'). In the second RSID field, because there is no single-quoted type, the editor searches back in the data for the first TNAM field and takes that data as the resource type.

Fixed-point numbers


Fixed point numbers are integers whose bits are divided into two sets. The upper (more significant) set is the signed integral part of the number, and the lower (less significant) is the binary fractional part of the fixed-point number. The two parts of the number are separated by an implicit fixed decimal point. FIXD fields correspond the Mac Fixed data type [16.16]. FRAC fields are the same as the Mac Fract data type [2.30]. SFRC fields are the same as SmallFract data types [0.16] used in certain color models. FWID (Font Width) fields are used in various font-related resources [4.12]. Finally, FXYZ fields are used in some other color models [1.15]. All of these except the SFRC type display the data as signed fixed-point numbers.

Floating-point numbers


Standard IEEE 32-b it and 64-bit single- and double-precision floating point numbers get parsed by the REAL and DOUB field types. EXTN parses the 68k 80-bit SANE floating point numbers; XT96 parses the 96-bit extended SANE floating point values, and UNIV parses the old THINK C Universal format 96-bit extended numbers. As far as PowerPC code is concerned, you only need to deal with REAL and DOUB floating point data.

Resorcerer's floating point support got added to the template system after developers working for a division of General Electric that sent balloons up into the atmosphere for data collection called saying they were keeping large amounts of floating point radar information in resources and needed to edit their data directly.

Creation and modification times


These two fields parse a 32-bit unsigned long number, and display it as the time and date as the system interprets it (number of seconds since Jan 1, 1904). Any MDAT field (modification date) is automatically adjusted to be the current time and date when you close the resource's editing window after using the Data Editor to change any field in the resource.

Script, language, and region codes


Each of these parses a signed 2-byte integer, the same as a DWRD. However, when the editor displays the value, it automatically provides a popup menu from which to choose all the standard values for the various codes, so that you don't have to remember or lookup which number stands for which language or region. These were implemented so that templates with these codes in them wouldn't also have to have copies of the long list of CASE fields (see below) that normally would be used to build the popups.

RGB colors and color tables


The COLR field parses an RGB triplet: 3 2-byte integers, for the red, green, and blue color components, in that order. The Data Editor then displays the field in both numeric and graphic form, and you can change all three fields simultaneously using the system color picker.

The CLUT field parses an entire Color Lookup Table data structure into one hex block. It was implemented to make it easier to parse embedded cluts in 'PICT' data as single hex blocks.

QuickDraw Rectangles and Points

RECT, PNT (the point field type ends in a space)

The 'PNT' field parses a pair of signed short QuickDraw coordinate integers (vertical coordinate first), as in a Point data type. The RECT field does the same for Rect data types, and the Data Editor allows you to set the rectangle coordinates to new values graphically, using a marching ants marquee. If the marquee is in front of and graphically contained within the content area of any other Resorcerer window, the coordinates recorded are converted to local coordinates for that window; otherwise, the values placed into the RECT field are in global screen coordinates.

Alignment, pad, and filler bytes

AWRD (= AL02), ALNG (= AL04), AL08, AL16, FBYT, FWRD, FLNG, Fnmm)

Unlike C, Resorcerer (as well as Rez and ResEdit) templates perform no hidden data padding or alignment unless you explicitly declare it in the template. Given the myriad problems hidden alignment and padding causes developers, this is a good thing. However, it means that any data field, including numerical integers and floats, can occur at any byte offset, if you design the template that way (usually at some cost in efficiency, which on older 68000 systems can run to a 100% loss when the machine crashes).

The AWRD, ALNG, AL08, and AL16 fields allocate a variable number of 0 or more pad bytes so as to ensure that the following field will start on a byte boundary (as counted from the start of the resource data) divisible by the number 2, 4, 8, or 16 respectively.

The FBYT, FWRD, FLNG, and Fnmm fields declare filler bytes of various fixed lengths (1, 2, 4, and 0xnmm). Filler bytes are uneditable and generally set to 0. Filler bytes are typically used to declare space within the data structure that will be used by code at runtime (for instance, to cache a Handle), but which has no meaning within the context of editing the resource data "offline".

ASCII characters, 4-byte literal type codes, and pure ASCII text


The CHAR field type parses and displays a single-character ASCII byte. The TNAM (Type Name) field parses a 4-character ASCII literal.

The TXTS field parses ASCII data until the end of the resource or until the end of an embedded, previously sized block of data within the resource. This field was implemented to fix the problem in the template distributed with ResEdit, which incorrectly declares a 'TEXT' resource as a null-byte terminated C string.

The Tnmm field declares a fixed-length buffer of 0xnmm bytes in which to expect 0 or more bytes of ASCII text. If the length of the text is less than 0xnmm bytes, the remaining bytes are set to zero-valued pad bytes.

Variable-length ASCII character strings


The PSTR field parses a Pascal-style string: a length byte followed by that many bytes of ASCII data. The WSTR field does the same, only the length is stored in a 2-byte integer; the LSTR field stores the length in a 4-byte long. The ESTR field (even-length string) also parses or creates a Pascal string, but if the length of the data (including the length byte) is odd, it appends an extra zero pad byte. At first glance this might appear the same as the sequence [PSTR, AWRD], but there is a subtle difference: it's the same only if the PSTR begins on an even byte offset to begin with. The OSTR field is the opposite of the ESTR field. It adds the pad byte to make the total Pascal string storage always an odd number of bytes and should only be used for parsing certain ancient resources. Similarly, the PPST field was implemented as a hack in order to be able to describe certain MPW resources whose data was stored ESTR style, except that the extra pad byte was incorrectly included in the length byte (which makes it impossible to tell whether it's a pad byte or a data byte with value 0).

The CSTR, ECST, and OCST fields are equivalent to the PSTR, ESTR, and OSTR fields, only they operate on arbitrary-lengthh, null-byte-terminated C-style strings, as opposed to initial-length-byte Pascal-style strings.

Fixed-length ASCII character string buffers

Pnmm, Cnmm

These two fields each allocate a block of 0xnmm bytes and interpret the dat a in the block as either a Pascal or C string, followed by as many zero-valued pad bytes as are needed to fill the block.

The Pnmm field was designed to work in exactly the same way as all other Xnmm type fields: the field type declares a block of data of length 0xnmm bytes, and whatever gets stored in the block is interpreted according to X. Thus, the Cnmm, Fnmm, Hnmm, Pnmm, and Tnmm fields all indicate their sizes in exactly the same manner. I felt that consistency on this front was important. ResEdit interprets the Pnmm field differently, choosing to break consistency within the TMPL language in favor of making this one field conform to how such fields are declared in Pascal or C (sort of, since Str255's aren't declared as Str0FF's). Resorcerer's Data Editor therefore supports both interpretations, on th e assumption that developers almost never allocate an odd number of bytes for the fixed-length buffer. The editor checks all Pnmm fields and if it finds one where 0xnmm is odd (as it is in ResEdit for an even-length buffer), it will give the user the opportunity to use ResEdit-style parsing.

Raw hex byte dumps


These fields parse and make editable blocks of bytes and present them as untyped hex data. With the first six types, the size of each block is taken from the initial byte, short, or long field. For instance, the BHEX field could be used to parse a Pascal string, only it would show the data in hex, not ASCII. The 'SHX' variants include the size of the size field in the count; the 'HEX' fields don't.

The HEXD field (Hex Dump), as originally defined in ResEdit, simply says take the rest of the resource data and edit it as untyped hex bytes. The HEXS field is similar, but is used for embedded hex dumps whose block sizes have been declared earlier.

68K disassembled code dumps


This is the same as HEXD, except that it asks the hex editing display to show the data as disassembled 68K code as well as in hex.

Automatically computed array repeat counts


You can group a set of fields together and ask that the group be repeated until a condition is met. (In Rez, these are declared as arrays.) Usually this condition is given as an explicit repeat count in the data itself. The BCNT, WCNT, and LCNT fields each parse the count for the next repeated group of data fields, using an unsigned 1-, 2-, or 4-byte integer count (byte, word, or long, respectively). The WCNT type is the same as ResEdit's OCNT (one-based count) type. ZCNT (zero-based count) fields specify a 2-byte count that is 1 less than the number of repeated items that follow. The LZCT does the same, but stores the count (minus 1) in a 4-byte long.

One important difference from ResEdit in how Resorcerer implements these counts is that in ResEdit, the count field has to immediately precede the start of the group of array item; in Resorcerer, as in Rez, the count can occur much earlier in the data, with intervening fields between the initial count and the array of repeated items.

The FCNT (Fixed Count) field specifies a fixed-length count, where the count is not in the data at all, but taken from the field label string in the TMPL itself.

The BCNT field was originally implemented in order to build a TMPL for MPW Commando resources, as well as just plain generality. The FCNT field was first implemented for the benefit of parsing certain ColorSync resources.

Groupings of fields into repeated array items


These "field" types don't represent any data fields per se; rather, they declare the bounds of a subsequence of template instructions that represent a repeated item. You should use one of LSTC, LSTZ, LSTB, or LSTS to declare the start of the group, and use LSTE to end it.

LSTC starts a one-based counted list, whose count has previously been parsed from the data using any of the BCNT, WCNT, OCNT, or LCNT fields. The LSTZ field does the same thing, only the counted list is 0-based, meaning the count field contains one less than the number of items. I avoid 0-based lists whenever possible.

The LSTB initiator says the list simply repeats indefinitely, without the benefit of an initial count, until the end of the resource.

The LSTS initiator says the list repeats until the number of bytes parsed reaches a previously declared size field's value. This is called a Sized List as opposed to a Counted List.

All of these list structures can nest. You can have an indefinite list of counted lists of sized lists, etc.

Recursive templates for trees


You can describe simple recursive trees of similar items by using the SELF template field type as the sole field in a counted list group. A copy of the entire template's set of fields will be used in place of the SELF field when you edit the data. Because the recursive list must be counted, there is no infinite recursive descent: the leaf lists in the tree must all have an item count of 0.

Collections of common, required, key, or default values


Most data field types in a Resorcerer template can be followed by a set of 0 or more CASE instructions. These do not parse any actual data, but rather declare a set of named values that the previous field data can take on. They function similarly to an 'enum' or set of '#defines'. In addition, the first CASE declaration in the list of CASE fields lets you install a non-zero initialization value into the data whenever you are creating a new resource, or new repeated item.

As we will see in the next section, the set of CASE fields also declare the set of legal key values for a switched alternate record structure.

Integer keys for switch statements


In the more complex resource data formats, it often happens that a field's value determines one of several alternate formats later in the data. The determining field is called the key, and the set of alternates formats are called the switched items. In Rez, such structures are described using a switch statement, and each alternate item is called a case.

KBYT, KWRD, and KLNG each declare a signed 1-, 2-, or 4-byte integer whose value is to be used as a key to choose from amongst several alternate formats.

KUBT, KUWD, and KULG are basically the same, only the key values are treated as unsigned decimal integers.

KHBT, KHWD, and KHLG are again basically the same, only the Data Editor presents the key values as unsigned hex. These fields are particularly useful in Resorcerer's 'PICT' template, since the opcodes in a 'PICT' are all documented in Inside Mac using hex constants, not decimal, and each opcode is really a key value for alternate opcode data formats that follow.

The declaration of the set of legal key values follows the keyed field type as the usual set of CASE fields. This allows the Data Editor to collect the symbolic descriptions of the cases into a popup menu in the usual manner, making interactive editing of the key field very easy.

The KRID field is special: it does not declare a data field. Rather, it declares a pseudo-data field whose value is actually the current resource ID of the resource whose data the template is being used to edit. This makes it possible for the template to declare completely different data formats dependent solely on the resource ID (which is meta-information about the resource data) rather than on a previous key field in the data itself. The KRID field was originally implemented in order to deal with certain MPW and other older resources ('PREC's); however, its use is highly discouraged, since it obviates the reason for having a resource type attribute in the first place.

Character and literal type keys for switch statements


These declare 1- and 4-byte ASCII character literals whose values are to be keyed off of. The KCHR field is the keyed version of the CHAR field; the KTYP field is the keyed version of the TNAM field (which is the same as an OSType or ResType or FourCharCode).

Groupings of fields into alternate (keyed or switched) data structures


Following a key field and its set of n CASE declarations, there must be n alternate data formats, one for each CASE. The template field sequences describing each of these alternates must be delimited by a KEYB...KEYE pair. The label of the KEYB field must be the same as the character value of the earlier CASE declaration.

Automatically computed data sizes (in bytes)


Many data formats contain embedded sizes of sub-areas of the data. This is very important fo r desiging extensible formats, because they allow old code to traverse newer formats. The BSIZ, WSIZ, and LSIZ fields each store an unsigned byte count into a 8-, 16-, or 32-bit integer, respectively. The count stored is the number of bytes in the data, beginning at the first byte after the size field and continuing up to the next next matching SKPE field. The BSKP, WSKP, and LSKP fields are the same, except that the byte count they store includes their own sizes (e.g. an WSKP data field can never be less than 2 bytes).

The SKP variants were originally implemented first, in order to edit balloon help resources. This flavor of size field allows the format parsing code to skip an internal data block by simply by adding the value of the field at that offset into the data to the offset itself to get to the first byte offset after this sized block of data. Consequently, I called these fields "skip offsets", which is what the "SKP" part of the field types derives from. The SKPE (Skip End) field doesn't parse any data; it simply delineates where to stop counting bytes, and as such terminates the byte-counted area of the template for all 6 flavors of sizes.

Data insertion and deletion

+BYT, +WRD, +LNG, +nmm, +PST, +EST, +CST
-BYT, -WRD, -LNG, -nmm, -PST, -EST, -CST

Changing the structure that a template describes is as easy as inserting or deleting a field type using the Template Editor. Unfortunately, if you've already built resource data with the old template, the newly changed template won't be able to parse the old data correctly. This problem becomes particularly acute when the changed template fields are part of any repeated or keyed items. How do you change the old data at the same time as the old template?

The data insertion and deletion fields help you solve this problem. The insertion field types all begin with the '+' character; the deletion fields all begin with a '-'. An insertion field in a template tells the Data Editor to create the field when the old data is opened for editing, and to leave the data there when closing the resource. The deletion fields work exactly oppositely. It parses the old data field normally when you open the resource, but deletes the field when you close it. If an insertion or deletion field is part of a repeated item, it will do its work on every item in an existing array in a resource.

As usual, the 'BYT', 'WRD', and 'LNG' fields operate on 1-, 2-, and 4-byte fields; the 'nmm' field operates on 0xnmm bytes. The 'PST' fields insert or delete a Pascal string; the 'CST' fields do the same for C strings; and the 'EST' fields insert or delete even-Pascal strings (as declared by the 'ESTR' field).

Once you've changed the data to insert or delete fields, though, you have to remember to go back into the template and either remove any of the deletion fields, or change any of the insertion fields to the non-insertion equivalents, before opening the resource data again. You don't want to make the changes twice!

Template comments


You can place a DVDR field anywhere in the TMPL field sequence. It doesn't parse any data, and its label string serves as a comment that the Data Editor draws for you on the right side of the data display.

Endian parsing mode


Templates default to parsing multi-byte numerical fields in big-endian style, since this is standard on the Mac. However, you can change the current endian interpretation to little-endian by using the LNDN or LTLE fields (which don't parse any data). The variants that end in "NDN" are invisible in the data editor display; the variants that end in "E" are shown.

Data pre- and post-processing with code plug-in filters


Data formats can be arbitrarily complex, and it's quite easy to design a format that the simple parsing fields available in the TMPL "language" can't parse. Typically, any parts of the data format that depend algorithmically on other parts of the data can't be properly edited by a TMPL. Typical examples include encrypted or compressed data; fields whose values are arithmetic formulas dependent on other fields (e.g. rowBytes in a PixMap); checksums; etc.

If the first field in a TMPL is FLTR, the template is considered a filtered template. This means that a code resource of type 'FLTR' should accompany the template in the same file as the TMPL resource was found. The Data Editor will call the code resource to filter the data both on input to the TMPL parsing mechanism, and on output. Thus the FLTR code converts the initial Handle of data into an intermediate form that the TMPL describes. On output, the FLTR unconverts the data the TMPL describes, creating a Handle of data in its final form.


Resorcerer's TMPL language, which is a superset of ResEdit's, lets you easily describe and then interactively edit many different resource formats. Quite often, there is a one-to-one mapping from a Rez template to a Resorcerer template. Resorcerer is shipped with a great many templates for common Mac system and application resources that Apple engineers have designed using Rez.

A concise listing of all these template field types can be found at

Doug McKenna is the root hierarchæologist of Mathemæsthetics, Inc and has been a programmer for over 25 years. In addition to maintaining and enhancing Resorcerer® for the much of the last decade, he has worked on taxonomic database and music notation software. In his minimally-existent spare time, he enjoys gluing words together, hacks piano compositions, and researches geometric fractal tiling designs. Doug's last article for MacTech was FEZ: Frame Evading ZoomRects, which explained his award-winning "pushing the envelope" hack at MacHack '94. You can reach Doug at


Community Search:
MacTech Search:

Software Updates via MacUpdate

Bookends 13.2.5 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
Quicken 2019 5.11.2 - Complete personal...
Quicken makes managing your money easier than ever. Whether paying bills, upgrading from Windows, enjoying more reliable downloads, or getting expert product help, Quicken's new and improved features... Read more
Dashlane 6.1927.0 - Password manager and...
Dashlane is an award-winning service that revolutionizes the online experience by replacing the drudgery of everyday transactional processes with convenient, automated simplicity - in other words,... Read more
Capo 3.7.4 - Slow down and learn to play...
Capo lets you slow down your favorite songs so you can hear the notes and learn how they are played. With Capo, you can quickly tab out your songs atop a highly-detailed OpenCL-powered spectrogram... Read more
BetterTouchTool 3.153 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
calibre 3.46.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Firefox 68.0.1 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
Vivaldi 2.6.1566.49 - An advanced browse...
Vivaldi is a browser for our friends. We live in our browsers. Choose one that has the features you need, a style that fits and values you can stand by. From the look and feel, to how you interact... Read more
Daylite - Dynamic business organ...
Daylite helps businesses organize themselves with tools such as shared calendars, contacts, tasks, projects, notes, and more. Enable easy collaboration with features such as task and project... Read more
Vivaldi 2.6.1566.49 - An advanced browse...
Vivaldi is a browser for our friends. We live in our browsers. Choose one that has the features you need, a style that fits and values you can stand by. From the look and feel, to how you interact... Read more

Latest Forum Discussions

See All

Void Tyrant guide - Tips and tricks for...
Void Tyrant continues to get a lot of play in these parts. Probably because the game is just so deep and varied. The next stop on our guide series for Void Tyrant is class-specific guides. First up is the Knight, as it’s the first class anyone has... | Read more »
Summon beasts and battle evil in epic re...
Imagine a tale of conlict between factions of good and evil, where rogueish heroes summon beasts to aid them in them in warfare and courageously battle dragons over fields of scorched earth and brimstone - that's exactly the essence of epic fantasy... | Read more »
Upcoming visual novel Arranged shines a...
If you’re in the market for a new type of visual novel designed to inform and make you think deeply about its subject matter, then Arranged by Kabuk Games could be exactly what you’re looking for. It’s a wholly unique take on marital traditions in... | Read more »
TEPPEN guide - The three best decks in T...
TEPPEN’s unique take on the collectible card game genre is exciting. It’s just over a week old, but that isn’t stopping lots of folks from speculating about the long-term viability of the game, as well as changes and additions that will happen over... | Read more »
Intergalactic puzzler Silly Memory serve...
Recently released matching puzzler Silly Memory is helping its fans with their intergalactic journeys this month with some very special offers on in-app purchases. In case you missed it, Silly Memory is the debut title of French based indie... | Read more »
TEPPEN guide - Tips and tricks for new p...
TEPPEN is a wild game that nobody asked for, but I’m sure glad it exists. Who would’ve thought that a CCG featuring Capcom characters could be so cool and weird? In case you’re not completely sure what TEPPEN is, make sure to check out our review... | Read more »
Dr. Mario World guide - Other games that...
We now live in a post-Dr. Mario World world, and I gotta say, things don’t feel too different. Nintendo continues to squirt out bad games on phones, causing all but the most stalwart fans of mobile games to question why they even bother... | Read more »
Strategy RPG Brown Dust introduces its b...
Epic turn-based RPG Brown Dust is set to turn 500 days old next week, and to celebrate, Neowiz has just unveiled its biggest and most exciting update yet, offering a host of new rewards, increased gacha rates, and a brand new feature that will... | Read more »
Dr. Mario World is yet another disappoin...
As soon as I booted up Dr. Mario World, I knew I wasn’t going to have fun with it. Nintendo’s record on phones thus far has been pretty spotty, with things trending downward as of late. [Read more] | Read more »
Retro Space Shooter P.3 is now available...
Shoot-em-ups tend to be a dime a dozen on the App Store, but every so often you come across one gem that aims to shake up the genre in a unique way. Developer Devjgame’s P.3 is the latest game seeking to do so this, working as a love letter to the... | Read more »

Price Scanner via

Flash sale! New 11″ 1TB WiFi iPad Pros for th...
Amazon has the 11″ 1TB WiFi iPad Pro on sale today for only $1199.99 including free shipping. Their price is $350 off Apple’s MSRP for this model, and it’s the lowest price ever for a 1TB 11″ iPad... Read more
Weekend Deal: 2018 13″ MacBook Airs starting...
B&H Photo has clearance 2018 13″ MacBook Airs available starting at only $999 with all models now available for $200 off Apple’s original MSRP. Overnight shipping, or expedited shipping, is free... Read more
Apple has clearance 10.5″ iPad Pros available...
Apple has Certified Refurbished 2017 10.5″ iPad Pros available starting at $469. An Apple one-year warranty is included with each iPad, outer shells are new, and shipping is free: – 64GB 10″ iPad Pro... Read more
Apple restocks refurbished iPad mini 4 models...
Apple has restocked Certified Refurbished 32GB iPad mini 4 WiFi models for $229 shipped. That’s $70 off original MSRP for the iPad mini 4. Space Gray, Silver, and Gold colors are available. Read more
Apple, Yet Again, Is Missing An Ultraportable...
EDITORIAL: 07.19.19 Prior to the decision made by Apple earlier this month to retire the thin and light MacBook model with a 12-inch retina display, the Cupertino, California-based company offered,... Read more
Verizon is offering a 50% discount on iPhone...
Verizon is offering 50% discounts on Apple iPhone 8 and iPhone 8 Plus models though July 24th, plus save 50% on activation fees. New line required. The fine print: “New device payment & new... Read more
Get a new 21″ iMac for under $1000 today at t...
B&H Photo has new 21″ Apple iMacs on sale for up to $100 off MSRP with models available starting at $999. These are the same iMacs offered by Apple in their retail and online stores. Shipping is... Read more
Clearance 2017 15″ 2.8GHz Touch Bar MacBook P...
Apple has Certified Refurbished 2017 15″ 2.8GHz Space Gray Touch Bar MacBook Pros available for $1809. Apple’s refurbished price is currently the lowest available for a 15″ MacBook Pro. An standard... Read more
Clearance 12″ 1.2GHz MacBook on sale for $899...
Focus Camera has clearance 12″ 1.2GHz Space Gray MacBooks available for $899.99 shipped. That’s $400 off Apple’s original MSRP. Focus charges sales tax for NY & NJ residents only. Read more
Get a new 2019 13″ 2.4GHz 4-Core MacBook Pro...
B&H Photo has new 2019 13″ 2.4GHz MacBook Pros on sale for up to $150 off Apple’s MSRP. Overnight shipping is free to many addresses in the US: – 2019 13″ 2.4GHz/256GB 6-Core MacBook Pro Silver... Read more

Jobs Board

Best Buy *Apple* Computing Master - Best Bu...
**707083BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000045-Rockford-Store **Job Description:** **What does a Read more
Geek Squad *Apple* Master Consultation Agen...
**702908BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000360-Williston-Store Read more
Best Buy *Apple* Computing Master - Best Bu...
**711023BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000012-St Cloud-Store **Job Description:** **What does a Read more
*Apple* Systems Architect/Engineer, Vice Pre...
…its vision to be the world's most trusted financial group. **Summary:** Apple Systems Architect/Engineer with strong knowledge of products and services related to Read more
Best Buy *Apple* Computing Master - Best Bu...
**696259BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Store Associates **Location Number:** 001076-Temecula-Store **Job Description:** The Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.