Resource Mover Modula-2
Volume Number: 2
Issue Number: 3
Column Tag: Modula-2 Mods
A Resource Mover in Modula-2 
By Tom Taylor, Hewlett Packard, Santa Clara, MacTutor Contributing
Moving Resources in Modula-2
The Macintosh's built-in ability to deal with resources can both complicate and
simplify life for the Mac programmer. Resources allow many items that would
normally be hardcoded into a program to be separated from the code and made
independent of program compilation. Typical resources include windows, dialogs,
controls, and icons. Many utility-type programs need to move resources from one file
to another. This article will present the steps necessary to move resources and provide
the sources to a library module and a demonstration program.
Clearing a resource file
The first routine I needed while designing a module to copy resources was a
procedure to clear a resource file of all resources. In dealing with the Mac, it seems
like there's always a ToolBox routine at hand to do exactly what you want. In this case,
I could find no routine to clear a resource file. My first cut at writing a resource
clearing routine worked by finding all the resources that belonged to the desired
resource file and then individually removing the resources by calling RmveResource.
For some unexplainable reason, this method did not work. Sometimes it would take
more than one pass over the file to delete all the resources. Out of frustration, I
resorted to a more brute-force, direct technique. This method involved opening the
resource file using the File Manager and directly manipulating its contents to mimick
that of an empty, newly created resource file. Figure one shows the contents of a
resource file after it has been "cleared" by my ClearRsrcFile routine (see the
commented routine in the MoveResources.MOD file).
PROCEDURE ClearRsrcFile
(file : ARRAY OF CHAR) : INTEGER;
There are two ways to open a resource file. Normally, the Resource Manager's
OpenResFile routine is called. This routine looks only on the default volume for the
specified file (unless one passes the volume name as part of the filename; a no-no
according to Apple and might not work with the HFS). Therefore, always do a SetVol to
the volume containing the resource file before calling OpenResFile. It is interesting to
note that the Resource Manager in the new ROMs includes a call called OpenRFPerm that
allows you to specify the volume reference number along with the resource file (and
permission too!). The other way to open a resource file is with the File Manager's
FSOpenRF call. FSOpenRF treats the resource file as a traditional data file and
OpenResFile treats the file as a collection of resources. Since the ClearRsrcFile routine
needs to go in and fool with the resource file directly, I used the FSOpenRF call to open
the file.
Figure 1. A cleared resource file.
Copying a resource file
The next step in designing a resource copying module was to design a resource
copying routine. I wanted the routine to be very simple from a user's point of view.
The routine takes two resource file reference numbers, one the source and the other the
destination, and simply copies all resources from one file to the other. Other
parameters of the routine specify whether information about each resource should be
printed as the resource is copied and whether duplicate resources should be replaced or
flagged as an error. Finally, a fairly involved error record is passed to the resource
copying routine so that if an error occurs, the caller has a chance at doing some sort of
sophisticated error recovery.
PROCEDURE MoveRsrcs
(src, dest : INTEGER;
noisy : BOOLEAN;
allowDuplicate: BOOLEAN;
VAR error : RsrcErr);
The resource copying routine (called MoveRsrcs in the the MoveResources.MOD
file), basically follows these steps:
1- Turn off resource loading by calling SetResLoad(FALSE). This tells the Resource
Manager not to load the resource data associated with each resource into memory
(of course, those resources marked as "preloadable" will have already been loaded
by the OpenResFile call). After every Resource Manager call, the procedure
CheckError is called to check for a Resource Manager error. If an error did
indeed occur, resource loading is turned back on by calling SetResLoad(TRUE).
Leaving a program without setting resource loading back on causes serious
problems!
2- Find all the resources associated with the source resource file. We loop through
all the resource types and the various resources of each type (by calling
CountTypes and CountResources) and get a handle to each resource. Unfortunately,
we must look at every resource from every open resource file just to find the
resources that belong to a specific file. When you ask the Resource Manager for a
resource, it checks all of the open resource files and there is no way to limit its
search to one file (although the order of the search can be changed). The new
ROMs, however, now implement a number of new Resource Manager calls that
only search a single resource file (routines such as: Count1Resources,
Get1IndType, etc). Of course, by using any of the new ROM calls, the program
wouldn't work on a Mac with the old ROMs. The HomeResFile routine tells us
which resource file a resource belongs to. If the resource belongs to the source
file we are interested in, then the handle to the resource is saved by our module
in a linked list.
3- Loop through the selected resources. Each selected resource handle is removed
from the linked list.
a- Load the resource into memory by specifically calling LoadResource.
LoadResource will load the resource even though SetResLoad is FALSE.
b- Call GetResInfo to find out the resource's name, type, and id.
c- "Detach" the resource with DetachResource. In other words, tell the Resource
manager to "forget" about it.
d- Check to see if the destination resource file already contains the same resource
and handle a possible collision.
e- Add the resource to the destination resource file.
4- Turn resource loading back on (SetResLoad(TRUE)) and return.
Step 2 mentioned that the resource manager searches all the open resource files
when performing various operations. In the case of MacModula-2, these files could
include: the System file, the Modula-2 interpreter, the .LOD file that uses the resource
copier module, the source resource file (the one we're copying), and the destination
resource file (the one we're copying to). Actually, the Resource Manager keeps a linked
list of all the open files and it sequentially searches the files in the list. By calling
UseResFile, one can change the order of this linked list. In fact, UseResFile is called in
a number of places where it is desireable that either the source or destination file be
searched first.
Figure 2. MoveResource program.
An applications program
The sample application program provides a front-end to the MoveResource
module (see figure 2). The program (called MoveResources.MOD) displays the
SFGetFile dialog box and prompts the user to select a source resource file. If the file
has a resource fork, the user is asked to select a destination resource file and decide
whether the destination resources should be cleared. Finally, the resources are copied
from the source to the destination file.
Since the Mac is so tied to resources, it's important that we understand how to
manipulate these resources. I hope that you will be able to make use of the code or
concepts discussed in this article in your own projects.
----------- MoveResources.DEF -----------