Resource Templates
Volume Number: 14
Issue Number: 9
Column Tag: Tools Of The Trade
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
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;
integer;
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;
#endif
------------------------------------
ResEdit TMPL
RECT BoundsRect
DWRD ProcID
BOOL Visible