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

Tidy Up 5.3.7 - Find duplicate files and...
Tidy Up is a full-featured duplicate finder and disk-tidiness utility. Features: Supports Lightroom: it is now possible to search and collect duplicates directly in the Lightroom library. Multiple... Read more
Pinegrow 5.97 - Mockup and design web pa...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
BlueStacks 4.210.0 - Run Android applica...
BlueStacks App Player lets you run your Android apps fast and fullscreen on your Mac. Feature comparison chart How to install Bluestacks on your Mac Go to MacUpdate and click the green "Download"... Read more
WhatsApp 2.2027.10 - Desktop client for...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Art Text 4.0.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
Adobe Dreamweaver CC 2020 20.2 - Build w...
Dreamweaver CC 2020 is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Dreamweaver customer). Adobe Dreamweaver CC 2020 allows you to... Read more
Adobe Acrobat DC 20.009.20074 - Powerful...
Acrobat DC is available only as a part of Adobe Creative Cloud, and can only be installed and/or updated through Adobe's Creative Cloud app. Adobe Acrobat DC with Adobe Document Cloud services is... Read more
beaTunes 5.2.10 - Organize your music co...
beaTunes is a full-featured music player and organizational tool for music collections. How well organized is your music library? Are your artists always spelled the same way? Any R.E.M. vs REM?... Read more
DiskCatalogMaker 8.1.5 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Meteorologist 3.4.1 - Popular weather ap...
Meteorologist is a simple interface to weather provided by It provides the ability to show the weather in the main menu bar, displaying more detail in a pop-up menu, whose contents are... Read more

Latest Forum Discussions

See All

Steam Link Spotlight - Disco Elysium
Steam Link Spotlight is a feature where we look at PC games that play exceptionally well using the Steam Link app. Our last entry was Signs of the Sojourner Read about how it plays using Steam Link over here. | Read more »
Distract Yourself With These Great Mobil...
There’s a lot going on right now, and I don’t really feel like trying to write some kind of pithy intro for it. All I’ll say is lots of people have been coming together and helping each other in small ways, and I’m choosing to focus on that as I... | Read more »
Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »
The King of Fighters Allstar's late...
The King of Fighters ALLSTAR, Netmarble's popular action RPG, has once again been updated with a plethora of new content. This includes battle cards, events and 21 new fighters, which increases the already sizeable roster even more. [Read more] | Read more »

Price Scanner via

$219 Apple AirPods Pro are back at Verizon, s...
Verizon has Apple AirPods Pro on sale again for a limited time for $219.99 on their online store. Their price is $30 off Apple’s MSRP, and it’s the lowest price we’ve seen for AirPods Pro. Available... Read more
Apple’s $779 13″ MacBook Air deal returns to...
Apple has clearance, Certified Refurbished, 2019 13″ MacBook Airs available again starting at $779. Each MacBook features a new outer case, comes with a standard Apple one-year warranty, and is... Read more
$200 13″ MacBook Pro discounts are back at Am...
Amazon has 2020 13″ 2.0GHz MacBook Pros on sale again today for $150-$200 off Apple’s MSRP. Shipping is free. Be sure to purchase the MacBook Pro from Amazon, rather than a third-party seller, and... Read more
Deal Alert! Apple AirPods with Wireless Charg...
Sams Club has Apple AirPods with Wireless Charging Case on sale on their online store for only $149.98 from July 6, 2020 to July 9, 2020. Their price is $50 off Apple’s MSRP, and it’s the lowest... Read more
Xfinity Mobile promo: Apple iPhone XS models...
Take $300 off the purchase of any Apple iPhone XS model at Xfinity Mobile while supplies last. Service plan required: – 64GB iPhone XS: $599.99 save $300 – 256GB iPhone XS: $749.99 save $300 – 512GB... Read more
New July 2020 promo at US Cellular: Switch an...
US Cellular has introduced a new July 2020 deal offering free 64GB Apple iPhone 11 smartphones to customers opening a new line of service. No trade-in required, and discounts are applied via monthly... Read more
Apple offers up to $400 Education discount on...
Apple has launched their Back to School promotion for 2020. They will include one free pair Apple AirPods (with charging case) with the purchase of a MacBook Air, MacBook Pro, iMac, or iMac Pro (Mac... Read more
July 4th Sale: Woot offers wide range of Macs...
Amazon-owned Woot is blowing out a wide range of Apple Macs and iPads for July 4th staring at $279 and ranging up to just over $1000. Models vary from older iPads and 11″ MacBook Airs to some newer... Read more
Apple Pro Display XDR with Nano-Texture Glass...
Abt Electronics has Apple’s new 32″ Pro Display XDR model with the nano-texture glass in stock and on sale today for up to $144 off MSRP. Shipping is free: – Pro Display XDR (nano-texture glass): $... Read more
New 2020 Mac mini on sale for up to $100 off...
Amazon has Apple’s new 2020 Mac minis on sale today for $40-$100 off MSRP with prices starting at $759. Shipping is free: – 2020 4-Core Mac mini: $759 $40 off MSRP – 2020 6-Core Mac mini: $998.99 $... Read more

Jobs Board

Physical Therapist Assistant - *Apple* Hill...
Physical Therapist Assistant - Apple Hill Rehab - Full Time Tracking Code 62519 Job Description General Summary: Under the direct supervision of a licensed Physical Read more
Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
*Apple* Mac Product Engineer - Barclays (Uni...
Apple Mac EngineerWhippany, NJ Support the development and delivery of solutions, products, and capabilities into the Barclays environment working across technical Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.