*** SPY (SPYne containers)
*** Document revision: 1.3
*** Last updated: March 11, 2004
*** Contributors/sources: John Iannetta
Created by John Iannetta around 1995, these are mostly found in
Compuserve's CBM applications forum, but do appear in the COMP.BINARIES.CBM
newsgroup as well. It is a self-extracting file, and does not employ any
compression. The word "SPYNE" does not represent any acronym, but is meant
to represent a "spine", with files linked together like a human spine.
This format has some similarities to LNX containers in that all the files
are simply stored (with no compression), one after the other, and are byte
aligned to take up multiples of 254 bytes (256 on a real 1541). This does
result in a little dead space at the end of each file stored, but its a
small price to pay for how easy it is to construct and break up files on a
real C64/1541.
SPYne containers do not contain a BASIC program (like LNX) at the
beginning telling you to "Use XXX to dissolve this file", since SPYnes are
self-extracting, and are meant to be loaded ",8,1" on a real C64. There is
no specific signature to determine if the file is actually a SPYne. SPYne
containers can store up to 144 files.
Each file inside the container can have up to 65535 blocks. However, the
container itself is limited to (best case) 65519 blocks total (65535 minus
15 blocks for extraction code, and a minimum of 1 block for directory
entries, 1-8 entries). Worst case for the container size is 65502 blocks
(15 blocks for extraction and 18 blocks for a directory of 137-144 files).
This many not make sense at first, but how can you load a SPYne file
which exceeds 258 blocks (the maximum memory of the C64)? SPYne files can
be as large as 65535 blocks, and it would seem impossible to work with
files this large. The answer is that the SPYne file loads at $02A7,
trapping the necessary vectors to prevent it from loading the entire file,
but just the extraction code. Neat trick!
The first 15 blocks (up to offset 3809 or $0EE1) of the file contain the
self-extracting code. It is an auto-running application, with a load
address of $02A7.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII
----------------------------------------------- ----------------
0000: A7 02 20 A0 E5 A9 0A 8D 1E D0 A9 16 8D 18 D0 A9 ????????????????
0010: 04 8D 1F D0 20 44 E5 A9 D8 85 FC A0 00 84 FB A2 ?????D??????????
0020: 04 A9 0D 91 FB C8 D0 FB E6 FC CA D0 F6 20 A5 FF ????????????????
Starting at offset $0EE2 (3810) is the central directory. This address is
exactly 15 blocks into the file (15*254=3810). Each directory entry is 32
bytes long, with the last two of these being "filler", and unused.
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII
----------------------------------------------- ----------------
0EE2: 82 00 00 30 32 2E 44 49 47 49 54 41 4C 20 4D 41 ???02.DIGITAL?MA
0EF2: 47 49 43 00 00 00 00 88 18 B5 FF 00 2B 00 00 00 GIC??????+??+???
0F02: 82 00 00 30 39 2E 2D 2D 2D 3E 20 42 59 20 3C 2D ???09.--->?BY?<-
0F12: 2D 2D 2D 00 00 00 00 00 7A 44 FF 00 2D 00 00 00 ---?????zD??-???
0F22: 82 00 00 30 33 2E 2D 3E 20 46 4F 52 43 45 53 20 ???03.->?FORCES?
0F32: 3C 2D 2D 00 00 00 00 11 BE 89 FF 00 20 00 00 00 <--?????????????
0F42: 82 00 00 30 37 2E 2D 3E 20 4F 46 20 45 56 49 4C ???07.->?OF?EVIL
0F52: 20 3C 2D 00 00 00 00 4F 78 11 FF 00 26 00 00 00 ?<-????Ox???&???
0F62: 82 00 00 30 34 2E 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D ???04.----------
0F72: 2D 2D 2D 00 00 00 00 40 58 D2 FF 00 28 00 00 00 ---????@X???(???
0F82: 82 00 00 30 31 2E 20 52 45 4C 45 41 53 45 44 20 ???01.?RELEASED?
0F92: 4F 4E A0 00 00 00 00 05 D5 0F FF 00 29 00 00 00 ON??????????)???
0FA2: 82 00 00 30 35 2E 20 4A 41 4E 55 41 52 59 20 31 ???05.?JANUARY?1
0FB2: 53 54 20 00 00 00 00 F7 FA EC FF 00 24 00 00 00 ST??????????$???
0FC2: 82 00 00 30 38 2E 20 20 20 31 39 39 36 A0 A0 A0 ???08.???1996???
0FD2: A0 A0 A0 00 00 00 00 39 71 C8 FF 00 36 00 82 00 ???????9q???6???
0FE2: 00 30 36 2E 20 28 4D 4F 52 45 20 4C 49 4B 45 29 ?06.?(MORE?LIKE)
0FF2: A0 00 00 00 00 40 33 CF FF 00 32 00 00 00 82 00 ?????@3???2?????
1002: 00 31 30 2E 20 28 31 32 2F 32 38 2F 39 35 21 29 ?10.?(12/28/95!)
1012: A0 00 00 00 00 AD 1C 0F FF 00 2B 00 00 00 82 00 ??????????+?????
1022: 00 44 49 47 49 54 41 4C 20 4E 4F 54 45 A0 A0 A0 ?DIGITAL?NOTE???
1032: A0 00 00 00 00 49 B0 CB 00 00 14 00 00 00 00 00 ?????I??????????
Byte: $00: File type
supported values for this location are:
$81 - SEQ
82 - PRG
83 - USR
01-02: Undefined (00's for now)
03-12: Filename (padded with $A0's)
13-16: Undefined (00's for now)
17-18: File checksum (in low/high byte format)
19: LSU byte (see "INTRO.TXT" document for description of
"LSU")
1A: Last file marker
FF - more files in container
00 - last file in container
1B: Set to $00
1C-1D: File sector count (in low/high byte format)
1E-1F: Not used (and not present on a 254-byte boundary)
File type support is limited to valid files only. SPYnes cannot contain
write-protected, "splat" or DEL files. Without DEL type support, this means
that many "separator" files in the directory cannot be included. REL files
are partially supported, as only the data portion is copied, and its
filetype is converted to USR format.
The checksum at byte offset 17-18 is a simple 16-bit addition (without
carry) of the entire file, but does not include the directory entry
information.
Looking at the above HEX dump, at address $0FE0 a new filename starts.
This is two bytes earlier than expected. This occurs because the address
$0FE0 is at a "254-byte boundary address", meaning it is divisible by 254,
with no remainder. Only in the directory area is this boundary important,
and when it happens, the last two "filler" bytes in the directory entry
don't exist.
SPYne supports two extraction methods, fast and slow. The fast method is
destructive in that is just breaks up the file into sections, only works on
a 1541/1571 drive, and has no checksum verification. The slow method should
work on any device, is not destructive to the original file, and uses the
checksum in the directory entry to verify the data integrity.
File data starts in the next block following the end of the directory.
You only know where the first file's data starts once the directory has
been completely read. Since the extraction code takes up 15 blocks, and
each 8 files take up another block, we can calculate how many blocks into
the container the actual file data starts.
If we have 11 files, we have two directory blocks (one full with 8
entries, one partial with 3 entries). Therefore the first file's data
starts at block 17 (17*254 = 4318, or $10DE). The second file's starting
position can be calculated by adding the block count of the first file
(multiplied by 254), and adding this to the first files starting position.
|