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

Audio Hijack 3.8.9 - Record and enhance...
Audio Hijack (was Audio Hijack Pro) drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio... Read more
macOS Server 5.12 - Quickly and easily t...
macOS Server makes it easy to configure and monitor Mac, iPhone, iPad, and Apple TV devices and network storage volumes. Here’s what you’ll get with macOS Server: Profile Manager Mobile device... Read more
Chromium 98.0.4755.0 - Fast and stable o...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 98.0.4755.0: Fixes and improvements. A list... Read more
Firefox 95.0 - 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
Apple Remote Deskto‪p 3.9.5 - Client com...
Apple Remote Desktop is the best way to manage the Mac computers on your network. Distribute software, provide real-time online help to end users, create detailed software and hardware reports, and... Read more
SpamSieve 2.9.47 - Robust spam filter fo...
SpamSieve is a robust spam filter for major email clients that uses powerful Bayesian spam filtering. SpamSieve understands what your spam looks like in order to block it all, but also learns what... Read more
RetroArch 1.9.14 - Game emulator.
RetroArch is most popularly known for being a program with which you can play many emulators and games, which have all been customized and tailor-ported to the libretro API. It is designed to be fast... Read more
Art Text 4.1.1 - $29.99
Art Text is graphic design software specifically tuned for lettering, typography, text mockups and various artistic text effects. Supplied with a great variety of ready to use styles and materials,... Read more
Sparkle Pro 3.1.7 - Visual website creat...
Sparkle Pro will change your mind if you thought building websites wasn't for you. Sparkle is the intuitive site builder that lets you create sites for your online portfolio, team or band pages, or... Read more
MarsEdit 4.5.6 - Quick and convenient bl...
MarsEdit is a blog editor for OS X that makes editing your blog like writing email, with spell-checking, drafts, multiple windows, and even AppleScript support. It works with with most blog services... Read more

Latest Forum Discussions

See All

‘Monster Rancher’ and ‘Monster Rancher 2...
Back in August, Koei Tecmo Europe and America announced a localization of Monster Rancher 1 & 2 DX for iOS, Nintendo Switch, and PC. Today, the bundle has gone live on all three platforms, but the iOS versions are also available separately in... | Read more »
‘Warhammer Quest: Silver Tower’ Adds the...
Warhammer Quest: Silver Tower (Free) from Perchang has gotten another big update today with the Witch Hunter champion joining in on the action. She arrives in Warhammer Quest: Silver Tower with a pair of pistols, new skills, and more. | Read more »
Out Now: ‘Legend of Mana’, ‘Evan’s Remai...
Each and every day new mobile games are hitting the App Store, and so each week we put together a big old list of all the best new releases of the past seven days. Back in the day the App Store would showcase the same games for a week, and then... | Read more »
SwitchArcade Round-Up: Garfield to Join...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for December 8th, 2021. In today’s article, we’ve got a bit of news about a certain cartoon cat joining a certain cartoon brawler. There’s also a surprisingly bumper crop of new releases... | Read more »
‘Metal Slug 5 ACA NEOGEO’ Review – Hamst...
Historically speaking, SNK isn’t shy about spreading its NEOGEO catalog around. Even when the console was active, ports of SNK’s biggest hits made their way to other consoles. Mobile devices have seen their fair share of NEOGEO love from SNK,... | Read more »
‘Pokemon Unite’ Holiday Event Detailed w...
Following the Pokemon Unite (Free) debut on Nintendo Switch and eventual release on iOS and Android, the game has been updated quite a bit with new licenses, fixes, and more. | Read more »
Rocket League Sideswipe’s latest patch a...
The mobile version of Rocket League is quite a hit! Rocket League Sideswipe was launched last week and its first season is in full swing. So far, the game has managed to get a high rating of 4.7/5.0 stars on Google Play. [Read more] | Read more »
Our 2016 Game of the Year ‘Crashlands’ I...
Butterscotch Shenanigans’ brilliant Crashlands is coming to Apple Arcade as an App Store Great in the form of Crashlands+ (). Ever since Crashlands hit iOS and other platforms, it has gotten tons of updates with new features, quality of life... | Read more »
‘Alpha Mission II ACA NEOGEO’ Review – M...
Of the three games that Hamster has selected for its initial spate of Arcade Archives releases, Alpha Mission II ($3.99) is the oddball of the bunch. Metal Slug and Samurai Shodown are both iconic franchises that were born on the NEOGEO, endured... | Read more »
‘Hatsune Miku: Colorful Stage’ Is Out No...
Following SEGA’s release date announcement for the global release of Hatsune Miku: Colorful Stage (Free), the game has gone live on iOS and Android wo | Read more »

Price Scanner via

New Verizon Holiday 2021 promo: Get a free Ap...
Verizon is giving away 64GB Apple iPhone minis to customers who choose this phone and open a new line of service. Offer is available online only, and no trade-in is required. Price of the phone is... Read more
Cheapest new Macs of the season: 3.6GHz Intel...
B&H Photo has last year’s Intel-based 3.6GHz 4-core Mac mini on clearance sale for only $529 for Black Friday 2021 only. Their price is $270 off original MSRP for this mini. It’s in stock today,... Read more
The cheapest iPads for sale at Apple this Hol...
Apple has Certified Refurbished 2020 7.9″ WiFi iPad mini 5 models with Retina displays available for up to $80 off original MSRP, starting at only $339. Each iPad comes with Apple’s standard one-year... Read more
These M1 models at Apple for only $849 are th...
Apple has restocked a full line of 2020 13″ M1 MacBook Airs, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the cheapest M1-powered MacBooks for sale today... Read more
In stock: 14″ M1 Pro with 10-Core CPU for $24...
Amazon has the new 14″ M1 Pro MacBook Pro with a 10-Core CPU and 16-Core GPU in stock today and on sale for $2449.99 including free shipping. Their price is $50 off Apple’s standard MSRP for this... Read more
New Verizon 2021 Holiday deal: Buy one iPhone...
Buy one iPhone 13 on Verizon’s online store during their Holiday 2021 sale, and get a second iPhone 13 for free through December 31, 2021. At least one new line of service required, but there is no... Read more
Holiday Sale: 13″ M1 MacBook Airs for $100-$1...
Amazon has launched a new Holiday 2021 MacBook sale with Apple 13″ M1 MacBook Airs discounted up to $150 off MSRP this week, starting at only $899. Their prices are the lowest available for new... Read more
Lowest price this Holiday season: Apple’s M1...
Amazon has Apple M1 Mac minis in stock today and on sale for $130 off Apple’s MSRP, only $569.99, as part of their Holiday/Christmas 2021 Sale. Their price is the lowest we’ve ever seen for this... Read more
Apple now offering free overnight delivery on...
Apple is now offering free overnight delivery on all in-stock Macs, iPads, iPhones, TVs, and Watches, including certified refurbished products, purchased on their online store though 3:00pm local... Read more
These are Apple’s Christmas 2021 shipping cut...
Apple has announced shipping cutoff dates to receive various products in time for Christmas 2021. The following dates apply for Apple’s free shipping. Note the stock can vary, especially given recent... Read more

Jobs Board

*Apple* / Macintosh / Jamf / Adm Systems Adm...
…Administration **Duties and Responsibilities** + Configure and maintain the client's Apple Device Management (ADM) solution. The current solution is JAMF supporting Read more
Engineering Manager *Apple* - DISH (United...
…data-driven self-starter to guide the product development team for all Apple products concerning schedules, waiver and compliance requirements, device certification, Read more
Product Development Engineering Lead - *Appl...
…will be doing We are seeking an ambitious, data-driven thinker to shape the Apple Product Development team as our new Retail Wireless division continues to grow and Read more
Device Certification Engineer - *Apple* - D...
…will be doing We are seeking an ambitious, fluent innovator to shape our Apple Product Development team and the larger Retail Wireless division at a pivotal point Read more
Product Specialist - *Apple* - DISH (United...
…We are seeking a results-oriented, analytical thinker to curate and manage the Apple device portfolio for our new retail wireless division at DISH. The successful Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.