*** T64 (Tape containers for C64s)
*** Document revision: 1.5
*** Last updated: March 11, 2004
*** Contributors/sources: Miha Peternel

  This format, designed  by  Miha  Peternel,  is  for  use  with  his  C64s
emulator. It has a very structured directory with each entry taking  up  32
bytes, and a reasonably well-documented format.

  It has a large header  at  the  beginning  of  the  file  used  for  file
signature, tape name, number of directory entries, used  entries,  and  the
remainder for actual tape directory entries.

  Following immediately after the end of the directory comes the  data  for
each file. Each directory entry includes the information of where its  data
starts in the file (referenced to the beginning of the file),  as  well  as
the starting and ending C64 load addresses. From  these  addresses  we  can
determine how long the stored file is (end-start).

  Unfortunately, in the early days of the C64s emulator,  before  Miha  had
his MAKETAPE utility ready, another program called CONV64 was on the scene,
and it created faulty T64 files. The ending load address was usually set to
$C3C6 regardless of file size. Be aware that these files  are  still  quite
common on the Web and FTP sites.

Here is a HEX dump of the first few bytes of a standard T64 file:

        00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F        ASCII
        -----------------------------------------------   ----------------
000000: 43 36 34 53 20 74 61 70 65 20 69 6D 61 67 65 20   C64S.tape.image.
000010: 66 69 6C 65 00 00 00 00 00 00 00 00 00 00 00 00   file............
000020: 01 01 90 01 05 00 00 00 43 36 34 53 20 44 45 4D   ........C64S.DEM
000030: 4F 20 54 41 50 45 20 20 20 20 20 20 20 20 20 20   O.TAPE..........
000040: 01 01 01 08 85 1F 00 00 00 04 00 00 00 00 00 00   ................
000050: 53 50 59 4A 4B 45 52 48 4F 45 4B 20 20 20 20 20   SPYJKERHOEK.....
000060: 01 01 01 08 B0 CA 00 00 84 1B 00 00 00 00 00 00   ................
000070: 49 4D 50 4F 53 53 49 42 4C 45 20 4D 49 53 53 2E   IMPOSSIBLE MISS.
...
0003E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0003F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
000400: 1A 08 E4 07 9E 32 30 38 30 14 14 14 14 14 14 14   ................

  The first 32 bytes ($000000-00001F) represent the signature of the  file,
telling us it is a tape container for C64S. Note that it is padded with $00
to make the signature 32 bytes long.

000000: 43 36 34 53 20 74 61 70 65 20 69 6D 61 67 65 20   C64S.tape.image.
000010: 66 69 6C 65 00 00 00 00 00 00 00 00 00 00 00 00   file............

  It is important that the string "C64" be at the  beginning  of  the  file
because it is the string which is common enough to be used to identify  the
file type. There are several variations of  this  string  like  "C64S  tape
file" or "C64 tape image file". The string is stored in ASCII.

  The next 32 bytes contain all the info about the directory  size,  number
of used entries, tape container name, tape version#, etc.

000020: 01 01 90 01 05 00 00 00 43 36 34 53 20 44 45 4D   ........C64S.DEM
000030: 4F 20 54 41 50 45 20 20 20 20 20 20 20 20 20 20   O TAPE..........

Bytes:$20-21: Tape version number of either $0100 or $0101. I am  not  sure
              what differences exist between versions.
       22-23: Maximum  number  of  entries  in  the  directory,  stored  in
              low/high byte order (in this case $0190 = 400 total)
       24-25: Total number of used entries, once again  in  low/high  byte.
              Used = $0005 = 5 entries.
       26-27: Not used
       28-3F: Tape container name, 24 characters, padded with $20 (space)

  The next 32 bytes (and  on  until  the  end  of  the  directory)  contain
individual directory entries.

000040: 01 01 01 08 85 1F 00 00 00 04 00 00 00 00 00 00   ................
000050: 53 50 59 4A 4B 45 52 48 4F 45 4B 20 20 20 20 20   SPYJKERHOEK.....
000060: 01 01 01 08 B0 CA 00 00 84 1B 00 00 00 00 00 00   ................
000070: 49 4D 50 4F 53 53 49 42 4C 45 20 4D 49 53 53 2E   IMPOSSIBLE MISS.

Bytes   $40: C64s filetype
                  0 = free (usually)
                  1 = Normal tape file
                  3 = Memory Snapshot, v .9, uncompressed
              2-255 = Reserved (for memory snapshots)
         41: 1541 file type (0x82 for PRG, 0x81 for  SEQ,  etc).  You  will
             find it can vary  between  0x01,  0x44,  and  the  normal  D64
             values. In reality any value that is not a $00 is  seen  as  a
             PRG file. When this value is a $00 (and the previous  byte  at
             $40 is >1), then the file is a special T64 "FRZ" (frozen) C64s
             session snapshot.
      42-43: Start address (or Load address). This is the first  two  bytes
             of the C64 file which is usually the load  address  (typically
             $01 $08). If the file is a snapshot, the address will be 0.
      44-45: End address (actual end address in memory,  if  the  file  was
             loaded into a C64). If  the  file  is  a  snapshot,  then  the
             address will be a 0.
      46-47: Not used
      48-4B: Offset into the conatiner file (from the beginning)  of  where
             the C64 file starts (stored as low/high byte)
      4C-4F: Not used
      50-5F: C64 filename (in PETASCII, padded with $20, not $A0)

  Typically, an empty entry will have no contents at all, and not just have
the first byte set to $00. If you only set the C64s filetype  byte  to  $00
and then use the file in C64S, you will see  the  entry  is  still  in  the
directory.

0003E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0003F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

  Starting at $000400 (assuming a directory with 30 entries)  we  now  have
actual file data.

000400: 1A 08 E4 07 9E 32 30 38 30 14 14 14 14 14 14 14   .....2080.......

---------------------------------------------------------------------------

What it takes to support T64:

  This format has some advantages over D64's in that there is  very  little
wasted space, except for the empty directory entries. It is laid  out  very
logically, with entries and headers all being in 32-byte chunks, making for
easy support. There is also a signature, and the directory size  can  be  a
large as you need for expansion.

  One large drawback is it is not  meant  to  support  multi-file  programs
under C64s. If you have a program which requires several  sub-files  to  be
loaded, under C64s a T64 file will not work. It would be best to use a  D64
in this case.

  When removing a file from a T64, you must  remove  the  entry  completely
from the directory. Failure to do  so  results  in  the  file  still  being
visible to C64s. It is not even good enough to set the whole entry to zero,
but it must be *removed*.

  The directory also contains the load start and end addresses. Why?  Since
T64 was designed for C64s, having the load address was something useful  to
show when selecting files inside of C64s. However, the  end  address  would
have been better if it was replaced with "file size", so you  could  easier
determine the file size for display.

  While the directory design allows for C64 file types to be used, it would
appear to be a waste as T64 really only supports loadable files  (PRG)  and
nothing else. REL is out of the question.

  Also, since the filename entries are not padded with A0  characters  (but
rather with spaces), filenames can't have trailing spaces.

  As mentioned previously, there are faulty T64 files around with the 'end load
address' value set to $C3C6. In order to work around this bug,  here's  how
to work with T64 files without relying on this value:

  1. Read in the entire T64 header, ignoring the 'end load address' value

  2. Sort the list by ascending order of offset into the T64

  3. Determine the difference in size (in bytes)  between  the  first  file
     offset and the next one. Remember to add in  the  two  'load  address'
     bytes that are stored in the directory as they are part of the file.

  4. You should now have your file size, and therefore be able to calculate
     the 'end load address' value given the load address.


---------------------------------------------------------------------------

Overall Good/Bad of T64 Files:

  Good
  ----
  * The header  is  *adequately*  defined  (but  some  improvement  in  the
    description would be good)

  * Supports a 16 character filename

  * Has a verifiable file signature

  * The format is extendible (can add delete to even a full container,  the
    central directory doesn't have a small file limit)

  * If you pack the T64 directory full, you minimize the DOS cluster  slack
    space loss, since the file size is variable

  * Has a description field in the header

  * Can have loadable files with the same name(?)



  Bad
  ---

  * Filenames can't have spaces at the ends due to the  padding  characters
    being spaces ($20) and not the standard $A0 character

  * It is not designed to  support  multi-load  programs.  Unless  all  the
    emulators start supporting this, it would not be a  good  idea  to  use
    them this way.

  * Doesn't practically support >63 files (this is a  limitation  of  C64s,
    nothing more)

  * No directory customization, as zero-length files not  allowed  (minimum
    filesize is 2 bytes)

  * No actual file size for contained files is stored, so you need to use a
    poor method to determine the file size based on the load addresses

  * Can't easily re-write contained files as they are  blocked  in  by  the
    files around them

  * No REL file support, as format really only supports PRG's

  * Header could have been  laid  out  better,  to  make  it  a  much  more
    versatile format than it is now

  * Can't have $00's in a filename(?)

  * Even though you can set  the  directory  entry  to  be  the  real  1541
    filetype (SEQ, USR, PRG), C64s still sees them as PRG's (?)