NOTE: Strings are NOT required to end with a null byte if it fills the entire
field. However, if the string doesn't fill the entire field, the remaining
bytes should be null. All strings are made of 8-bit characters (only values
from 32 to 255 are allowed). If you print the strings using the C function
printf(), use a width specifier for strings (i.e. %.32s).

+------------------+------------------------------------------------+
| width (in bytes) |            description                         |
|------------------|------------------------------------------------|
|        4         | Identifier: the characters 'G' 'Y' 'M' 'X'     |
|------------------|------------------------------------------------|
|       32         | Song title                                     |
|------------------|------------------------------------------------|
|       32         | Game title                                     |
|------------------|------------------------------------------------|
|       32         | Game publisher                                 |
|------------------|------------------------------------------------|
|       32         | Name of emulator used to create the gym file   |
|------------------|------------------------------------------------|
|       32         | Name of person who created the gym file        |
|------------------|------------------------------------------------|
|      256         | Miscelaneous comments                          |
|------------------|------------------------------------------------|
|        4         | Loop integer (unsigned little endian). Zero if |
|                  | the gym should not loop. Otherwise it specifies|
|                  | the point (1 being the very beginning) at which|
|                  | looping begins in 1/60 seconds.                |
|------------------|------------------------------------------------|
|        4         | Specifies the uncompresed size (unsigned little|
|                  | endian) of the raw gym data if the gym data has|
|                  | been compressed with zlib (deflate algorythm). |
|                  | Zero if not compressed.                        |
|------------------|------------------------------------------------|
|        X         | raw gym data                                   |
+------------------+------------------------------------------------+

GYM players that do not have full support for this tag should check for the
identifier, and if the identifier is present, seek to (zero based) offset
428 and start playing.

The raw gym format works like this:  
 while (!EOF)
  switch (readbyte()) // readbyte() reads the next byte from the file
  {
   case 0: 1/60th of a second has elapsed; 
   case 1: ymport=0; ymreg=readbyte(); ymdata=readbyte();
   case 2: ymport=1; ymreg=readbyte(); ymdata=readbyte();
   case 3: write readbyte() to psg port
  }

Player that support the loop integer should loop like this:
 1. Start playing the gym data from the very begining to the very end.
 2. At the end, seek to the point specified by the loop integer.
 3. Play to the very end.
 4. Repeat steps 2 and 3.

zlib is located at http://www.cdrom.com/pub/infozip/zlib/zlib.html

Here is an example of how the header structure looks in the C language
(assuming int is 32-bit and char is 8-bit and the machine is little endian):

struct GYMTAG {
    char gym_id[4];
    char song_title[32];
    char game_title[32];
    char game_publisher[32];
    char dumper_emu[32];
    char dumper_person[32];
    char comments[256];
    unsigned int looped;
    unsigned int compressed;
};