.!****************************************************************************
.! 
.! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
.!
.! ** Professional GEM ** by Tim Oren
.!
.! Proff File by ST enthusiasts at
.! Case Western Reserve University
.! Cleveland, Ohio
.! uucp : decvax!cwruecmp!bammi
.! csnet: bammi@case
.! arpa : bammi%case@csnet-relay
.! compuserve: 71515,155
.!
.!****************************************************************************
.!
.!
.!****************************************************************************
.!
.!			Begin Part XVII
.!
.!****************************************************************************
.!
.PART XVII PC/ST Resource Converter
.PP
This the seventeenth installment of ST PRO GEM, the
first to feature a complete GEM application.  The program
converts resource files between the ST (68000) and IBM PC
(Intel) formats used by the respective versions of GEM and
the Resource Construction Set.
.PP
The Resource Converter will, for the most part, be of
direct use only if you are doing cross-development of GEM
software on these two systems.  In this case, you will want
to read this entire article, starting with the "What It Does"
heading.  You may also be interested in an article on PC/ST
conversion written by Mark Skapinker of Batteries Included,
which appears in the Fall issue of START magazine (available
September 1986).
.PP
If you are not doing cross machine development, you can
still get something out of this column.  Reading the program
code and following the discussion, you will find practical
examples of using GEM dialogs and following the internal
structure of a resource file.  Finally, there is a good deal
of standard code for GEM initialization, AES utility
functions, and GEMDOS file handling which you can extract for
your own uses.  If you fall in this category, skip the first
parts of the column, and resume reading at the "How it Works"
heading.
.PP
     The download for this column is a set of source and
binary files located on DL3 of the ATARI16 SIG, PCS-58.  The
files and their contents are:

     RCMAIN.C   -  Download and rename to RSCVMAIN.C
                    This is the C source for main routine
     RCFILE.C   -  Download and rename to  RSCVFILE.C
                    This is the C source of GEMDOS utilities
     RCLIB.C    -  Download and rename to RSCVLIB.C
                    C source of AES utility functions
     RSCONV.PRG -  Linked binary of converter
     RSCONV.RSC -  Binary resource image (ST format)
     RSCONV.DFN -  Symbol file for resource (ST format for
                    RCS 2.0)
     RSCONV.H   -  Object/tree name file for resource
     RLINK.SH   -  Download and rename to RSCVLINK.SH
                    C-shell script for linking RSCONV
     SYLINK.SH  -  Download and rename to SYMLINK.SH
                    Another script, used by RSCVLINK.SH
.PP
The final two files will be of use only if you are using Dave
Beckemeyer's Micro C-Shell environment.  If not, you can
simply translate them to .BAT and/or .INP form for use with
the Atari batch program and linker.
.SH WHAT IT DOES
A converter program is necessary because of the
differing order of storage on the 68000 and Intel chips:  the
order of significance of bytes within words is reversed, as
well as the order of words within long (32-bit) quantities.
Attempting to load an unconverted resource on a GEM system
with the other architecture will result in a crash, because
all of the pointer and integer fields will be incorrect.
.PP
In addition, the format of symbol definition (DEF) files
differs between the PC and ST implementations of the RCS in
its first version.  In the latest version from DRI, the
formats do correspond, and the files now carry an extent name
of DFN.  However, the byte swapping problem must be corrected
in either format for the symbols to be correctly loaded.
     As final touch, the converter also checks to be sure
that a resource being loaded from the PC has its bit images
synchronized to an even byte boundary.  If this is not
corrected, the ST will suffer a bus error when attempted to
address the images with a word type operation, which will
certainly happen in either the RCS or the application itself
on the target system.
.SH OPERATION
When the Resource Converter loads, it presents an
initial dialog box.  (The converter does not use the menu
bar.) The dialog has action buttons at the bottom labelled
"Help", "Convert" and "Quit".  Clicking the Help button will
obtain a screen which summarizes these operating
instructions.  The Quit button terminates the program.
Clicking Convert initiates the program's action, according to
the options you have set in the rest of the dialog.
.PP
The top two buttons in the dialog establish the
direction of the conversion.  If you have built a resource on
the PC and want to move it to the ST, click Intel->68000.  If
you are moving the file from the ST to the PC, click
68000->Intel.
.PP
The next two lines in the dialog establish the file
extent names which will be used for the conversion.  The
input extent names are always on the left, no matter which
conversion mode you selected above.  By default, they are RSC
and DEF.  The output extents, on the right, are RS2 and DF2
by default.  The RSC/RS2 file extents are used for the
resource, and DEF/DF2 extents are for the symbol file.  Be
careful that the input files you use are actually of the type
(Intel or 68000) which you specified.  If you get it
backwards, the ST will most likely crash, though the input
files will not be harmed.
.PP
The three buttons below the file extents determine the
format of the input and output symbol files.  If you click on
DEF, the Resource Converter will assume that the input and
output symbol files are in the old (that is, version 1.1)
format used by the RCS.  If you click on DFN, the program
expects the new (version 2.0) symbol format.  If the input
symbol file extent is still set to "DEF", clicking this
button will also change it appropriately.  (Note that the DEF
and DFN formats are in fact IDENTICAL on the PC ONLY.  To
"change formats" ON THE PC, you need only change the file's
extent name, for example, rename FOOBAZ.DEF to FOOBAZ.DFN.
On the ST, there is a real difference,and you must use the
DRI DEF2DFN.PRG utility to go from old to new.)
.PP
The last button option is (OFF).  Clicking this button
disables the symbol file conversion.  You may use this option
to keep better control over versions of your resource.  By
establishing the main version on either the PC or ST, and
converting only the resource file, not the symbols, you can
ensure that no one will use the RCS on the destination
machine to create a version which is different from the
source.
.PP
When the Convert button is clicked to begin execution,
the standard Item Selector is displayed.  Use it to find and
pick the input resource file which you want to convert.  The
Converter will use its main filename, substituting the
various extents, to find the input definition file, and
produce the output file names.  If the definition file cannot
be found in the same directory under the generated name, you
will be presented with an alert, asking you to abort the
conversion, continue without the symbol file, or specify a
new name and/or directory for the file.  If the output names
coincide with existing files, they will be overwritten.
.PP
While the conversion operation is occurring, a progress
indicator box will be displayed on the screen, with text
messages indicating the current phase of the operation.  When
the conversion is complete, you are returned to the initial
dialog, where you may quit or perform another conversion.
.PP
One last note on conversion, with a caution:  it is
possible to move files between Intel and 68000 even if you
have two different versions of the Resource Construction Set,
for instance, Version 2.0 on the PC and Version 1.1 on the
ST.  In this situation, you can take advantage of the
identity between symbol file formats on the PC.  Make a copy
of the PC symbol file into another file with the DEF extent,
and run the converter.  The output should load on the ST
version correctly.  However, if you move symbols between
different RCS versions, you MUST NOT use the "free strings"
and "free images" features of version 2 and then move the
symbols to version 1.  Doing so may result in spurious
assignment of the "free" symbols to trees and objects, and
you will (of course) not be able to edit the free images
and/or strings in the resource.
.SH HOW IT WORKS
For the ST-only developers now rejoining the discussion,
I will now take a look at the standard GEM initialization
code and the special dialog handling techniques which I have
used in the Converter.  Then we'll look at the guts of the
code, which threads through the resource to do the actual
conversion.  For those interested in the supporting code
libraries, the GEMDOS interface utilities in RSCVFILE.C were
described in column number 15.  The progress indicator
functions of RCSLIB.C were detailed in column 16, and
map_tree() and standard dialog handling techniques were
discussed in columns three through five.
.PP
There are a number of useful facts in rscv_init(), the
initialization code.  First, notice that the result of
appl_init is NOT assigned directly to gl_apid.  Due to a bug
in the appl_init binding the application ID is not returned
as the function value.  Instead it is returned to the global
variable gl_apid.  This bug wouldn't cause direct problems in
the resource converter, but it will in any program which uses
the ID when sending messages to its own pipe.
.PP
Next, an alert string to be displayed if the resource is
not found has been explicitly included, to avoid a "Catch-22"
situation.  You can easily create such a string by building
the alert in the RCS, using the C output option, and
extracting the string from the resulting file.
.PP
Rscv_init() then sets up its VDI handle, by getting the
physical workstation handle from graf_handle, and passing it
to v_opnvwk (open virtual workstation), which returns the
virtual workstation handle for use in VDI calls.  V_opnvwk
also returns the dimensions of the screen, which are copied
to GRECT scrn_area, and the number of color planes, which is
used to set up an MFDB for the screen:  scrn_mfdb.
.PP
The wind_get call for the working area of the DESK
window (number zero) results in the usable GRECT of the
screen.  This is different from scrn_area, because the menu
bar's rectangle is reserved for the system.
.PP
You may want to take particular notice of the vst_height
call, which reloads the character dimension variables.  The
values returned earlier by graf_handle are ALWAYS for the
monochrome (high resolution) system font, and they are not
appropriate for the low and medium resolution modes of the
ST.  Performing the vst_height call AFTER opening the virtual
workstation will get the correct dimensions.
.PP
Some of the environment variables which are set up by
rscv_init(), are not actually used in the resource converter.
I have included them because they are part of my "generic"
initialization procedures.
.PP
Finally, rscv_init() uses Malloc to reserve most of
memory as a working buffer for the resource conversion.
Notice that 4K are left free.  You must leave at least 2K,
and preferably a safety factor, or the AES will be unable to
allocate memory for the file selector dialog, and your
application will hang when calling fsel_input.  By the way,
an open virtual workstation uses about 8K, so you should do
your Mallocs after the workstation call.
.PP
We now turn our attention to do_mode(), which handles
the main dialog of the converter.  After getting the root
address of the dialog tree, the states of global variables
conv_def and new_dfn are used to set up the radio button
array for symbol file conversion.  Native_in is used to set
up the conversion type radio buttons.  The last
initialization step is to use the set_text() utility to link
the file extent strings into the appropriate editable
objects.  Notice that this version of set_text() allows the
string length to be explicitly supplied.  For an editable
text field object (G_FTEXT or G_FBOXTEXT), the length must be
one greater than the number of blanks in the editing
template.
.PP
Since there are TOUCHEXIT objects in the dialog, we
cannot use the standard hndl_dial() routine.  Instead, the
form setup and draw calls are coded inline.  The actual
form_do call is placed inside a loop.  If the object returned
is not one of the TOUCHEXIT objects, the loop is terminated.
.PP
The two objects DEFYES and DFNYES, which select the old
and new symbol file formats, respectively, have been made
TOUCHEXIT.  If either is clicked, the radio button processing
is done by the AES, but then control is returned from
form_do.  Do_mode() then tests the current input symbol file
extent.  If it is "DEF" and we are switching from old to new
mode, the extent is changed to "DFN".  When switching from
new to old mode, the reverse check is made.  In either case,
the disp_obj() utility is used to force an immediate redraw
before returning to form_do for further user input.
.PP
When the loop terminates, do_mode() cleans up the screen
with form_dial, and uses the selected() utility to retrieve
the status of the radio button arrays and update the global
variables.  Finally, map_tree() is used to apply the
deselection utility to all objects in the tree, leaving it
clean for the next invocation of do_mode().
.SH THE BELLY OF THE BEAST
The routine dconv() contains the code for actually
converting the resource.  About half of do_conv() is devoted
to accessing disk files, and correctly handling error
conditions which might arise.  The error recovery could
perhaps be handled more concisely with artifices like
"setjmp", but I have left it in-line for the sake of clarity.
.PP
Do_conv() also uses a collection of routines whose names
begin with "swap_" Swap_bytes() and swap_words() are the
workhorse routines.  They simply run through a given area of
memory, reversing every pair of bytes or words, respectively.
(Remember that the word swapper will only work on even byte
boundaries, or a bus fault will occur.) The other swap
routines do the fix up for one type of resource structure
each.  I'll take apart a couple in detail, so that you can
see the similarities in the others.
.PP
Now let's follow the do_conv() code.  The first item of
business is to use the get_file() utility, followed by
open_file(), to find and open the input resource file.
Again, you can see column 15 for a a discussion of these
routines, which will handle DOS errors if they occur.
.PP
The Boolean conv_def is true if we need to open a
symbols file.  If everything goes right, just substituting a
new extent name (from variable old_def), and doing the file
open will get the file.  If things foul up, do_conv() has to
recover gracefully.  So, it puts up the three button alert
NODEF.  The third button is an abort option;  if it's picked
we punt, closing the one open file and returning to the main
dialog.  Button one allows a continuation without the
definition file (conv_def is forced FALSE so the user won't
make the same mistake twice).  Button two says try again, so
get_file() is called to pick another file, and the whole
process repeats.
.PP
Once the input file(s) are open, the operation will run
to completion, assuming no disk errors.  The mouse form is
switched to an hour glass, and a progress indicator box is
initialized on the screen.
.PP
The first action is to bring in the resource header
only.  If the resource is not native, that is, is not in
68000 format, its bytes must be swapped before using any of
the counts and offsets.  Note:  if you've never dissected a
resource before, this would be a good time take a look at the
header format given in "gemdefs.h" in the Developer's Kit,
and the resource structure definitions in "obdefs.h".
.PP
After the swap, if necessary, the resource size field
can be used.  Before reading the rest of the resource, the
size must be compared against the size of the buffer
allocated during initialization.  If there isn't enough room,
the NOMEM alert is displayed and control returns to the main
dialog.  (Since the biggest resource is 64K, and the
Converter is rather small, this shouldn't ever happen.  But,
some people load up lots of desk accessories, so best to be
prepared.)
.PP
After completing the resource input, an (admittedly
kludgy) patch is made for the odd-byte-images problem.  If
the image offset pointer is odd, there will be problems on
the ST.  The fix made here relies on two facts.  First, all
images are an even number of bytes in size.  Second, the old
version of RCS DOES do an even byte synchronization AFTER
writing the images.  Therefore, if the images start on an odd
byte, they will end on an even byte, and have one unused
odd-addressed byte immediately following.  The fixup strategy
is to move all of the images up one byte, patch the offset in
the header accordingly, and leave the img_odd flag set so
that the bit image swap routine will also increment pointers
in the BITBLK and ICONBLKs which use the images.
.PP
If the resource being converted is native, we can do the
image fixup immediately.  If not, all of the other swaps have
to take first, because the long pointers in the BITBLKs and
ICONBLKs are in the wrong order.  (We don't have to swap
string data;  it's always stored in ascending order.)
.PP
Do_conv() calls subroutines to swap the tree index,
objects, TEDINFOs, ICONBLKs, BITBLKs, and free string and
images, in that order.  We'll look at their actual code
later.  When this is finished, one of two cleanup actions is
needed.  If the resource WAS native, everything is now
swapped except the header, which is finally reversed.  If it
used to be foreign (Intel), the pointers are now in proper
68000 order, so swap_images() can be called successfully.
.PP
Now it's time to write the converted resource, taking
care that no error results.  If no symbol file conversion is
needed, do_conv() is done.  The files are closed, the
progress indicator completed, and control returns to
rscv_run, which will set the cursor back to the arrow.
Otherwise, it's time to handle the symbols file.
.PP
The first two bytes in the definition file are always
the symbol count.  They are read into nsym, and a scratch
copy is made in reply, and swapped.  Just which version is
written to the output file depends on whether it is a DFN or
DEF file.  The new (DFN) format keeps a similar word order on
both the ST and PC.  For these files, the following code
amounts to a verbatim copy.
.PP
Nsym is now used as the control variable of a loop which
reads, converts, and writes one symbol entry on each
iteration.  In the old (DEF) file format, there was an extra
word in the value field of each symbol's entry on the ST.
Going from PC to ST, two padding zero bytes are added.  Going
the other way, they are read and discarded.  For the old
format, both the significant word of this field, as well as
the following word field (the type) are swapped.  The ten
symbol bytes are passed through verbatim in both new and old
format.
.PP
After swapping (old format) or simply copying (new
format) of the symbol file is completed, file and progress
box cleanup is done, and control returns.
.SH THE OL' SWITCHEROO
     As promised, let's now go and look at a sampling of
the structure swap routines:  one of the simplest (tree
index), one of medium complexity (objects), and the
worst of the bunch (bit images).
.PP
Swap_trees() is responsible for fixing the tree index.
Its location is found by adding an offset from the header
(rsh_trindex) to the base address of the resource, stored in
head.  (Notice that head was defined as a byte pointer when
the buffer was allocated, so I need to type coerce it to a
resource header pointer before making structure references.)
The number of trees is stored in the rsh_ntree header field.
Each index entry is a long pointer of 32-bits, so the total
size of the index may be found by multiplication.  Finally,
the swapping is done, first bytes within words, then words
within the long pointers.  (The order doesn't matter - work
it out!)
.PP
Swap_objs() takes care of swapping fields inside of
object structures.  It begins similarly to swap_trees(),
computing the base address of the objects from rsh_object,
and taking the count from rsh_nobs.  Since all of the objects
are contiguous in a resource produced by RCS, and all fields
of an object are words or longs, a byte swap is performed on
the entire block at once.  Now there are a couple of tricks.
Notice that "where" in this routine is typed as an object
pointer.  As the number of objects is counted down in the
loop, "where" is incremented.  Because of its type, its
actual pointer value will increase by sizeof(OBJECT) at each
iteration.  Inside the loop, only one long field, the
ob_spec, needs to be word swapped.  When the loop completes,
all object structures are fixed.
.PP
Swap_fstr() and swap_fimg() use code similar to
swap_trees().  The other resource structures, TEDINFOs,
ICONBLKs, and BITBLKs, are transformed by code similar to
swap_objs().  There is one subtlety here.  These structures
would normally be reaching by following an object's ob_spec
pointer.  To finesse a "swap now or later" ordering problem
with the objects, I have instead used the resource header to
find the structure arrays.  You SHOULD NOT use this technique
at run time, for two reasons.  First, if you do any object
patching on the fly, the correspondence between objects and
reference strucutres will be destroyed.  Second, there is no
way to name a non-object structure with the RCS, and
therefore no way to reliably retrieve it with rsrc_gaddr at
execution time.
.PP
Last but not least, swap_images() not only takes care of
switching bit image words, but also fixes image pointers as
necessary if an odd byte problem has been detected.  For
these reasons, swap_images DOES follow pointers from the
ICONBLKs and BITBLKs.  The loop structure of the two sections
of code will be familiar from swap_ibs() and swap_bbs().
Size fields within the structure are used to determine the
length of each image.  If the img_odd flag has been set, the
data pointer must be incremented BEFORE doing the swap, since
the underlying data has already been moved.
.SH PHEW!
This column was deliberately long, in hopes that even
those with no immediate use for this program will gain from
the discussion.  Do to space limits, the feedback is
postponed to episode number 18, which will be another helping
of "interface potpourri".  Ingredients will include the popup
menu code (finally), along with generic code for scrolling
windows, and building your own scroll bars within dialogs.
.!
.!
.!*****************************************************************************
.!*									      *
.!*				End Part 17				      *
.!*									      *
.!*****************************************************************************
