MegaTech VOL Format/Decoding Example
Decoding example for Cobra Mission's GC format.
Sample data from the second Girl's Photo in inventory, third GC entry in PIC3.VOL. Decoding routine provided by dascandy
d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
We will be decoding the byte sequence above. To start, we take the first two bytes to preload the bit buffer. The nibble buffer stays empty, and the back buffer is also empty.
- BITS: 1101 1000 1101 1000
- NIBBLE: empty
- BACKBUFFER: empty
- OUTPUT: empty
- CONSUMED INPUT: d8 d8
- REMAINING INPUT: 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
The first command we get is 110, copy 4 bytes from the input to the back buffer and output.
- BITS: 1 1000 1101 1000
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 (1 entry)
- OUTPUT: 01 01 01 01
- CONSUMED INPUT: d8 d8 01 01 01 01
- REMAINING INPUT: e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
The second command is also 110, so we do this same thing again.
- BITS: 00 1101 1000
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 (2 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0
- REMAINING INPUT: 55 e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
Now, the value we get from the bit buffer is 00. This is an code that needs an additional nibble, so we'll read it:
- BITS: 1101 1000
- NIBBLE: 5
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 (2 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55
- REMAINING INPUT: e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
We got a 5. This lands us in the 4-9 for that one, so we fetch another nibble (5) to get the amount to copy, and use the first 5 (minus 4) to get the offset to read at. That results in 7 values to copy from 2 entries back.
- BITS: 1101 1000
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 (2 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55
- REMAINING INPUT: e3 e3 e2 e2 61 61 a1 21 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
Now we get the 110 command twice more. Skipping ahead for those two:
- BITS: 00
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 (4 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21
- REMAINING INPUT: 1b ec 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
Reading the next command we get a command 00. Before we continue though, the bit buffer is empty and it *first* refills.
- BITS: 1110 1100 0001 1011
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 (4 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21
- REMAINING INPUT: 47 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
Now we run the second 00 command fetching its data. It needs a nibble to know what offset to run at, and it fetches a 7 for that - same as last, except a larger pointer, going 8 back. It fetches another nibble for the count, and gets the 4 (from the same byte). It will then copy 6 values (4 + 2) from an offset of 8 entries back. The compressor most likely stopped there to avoid copying the interruption.
- BITS: 1110 1100 0001 1011
- NIBBLE: empty
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 (4 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47
- REMAINING INPUT: 70 46 b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
We retrieve a command 1110; this refers to the copy move table. We also fetch a nibble to find out which subcommand it runs, and it's a zero. This copies a number of values from a short distance back. It starts by fetching a full byte - note that we are ignoring the nibble we have in the nibble buffer for this - and we get a 0x46. It splits this into a 2-bit index into the offset table getting an offset of -2, and a 6-bit count of entries to copy (to be increased by 17+1, so 24). We therefore copy from a relative offset of -2 entries, 24 times.
- BITS: 1100 0001 1011
- NIBBLE: 7
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 (4 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46
- REMAINING INPUT: b5 b5 ab a1 55 b2 81 94 88 94 37 b8 00 55 55
We get another 110, so we copy an entry to the buffer and output.
- BITS: 0 0001 1011
- NIBBLE: 7
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 (5 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1
- REMAINING INPUT: 55 b2 81 94 88 94 37 b8 00 55 55
Again, we get a 00, so we copy from the back. We first fetch the nibble value from the nibble buffer now, so we have a 7. The second nibble we fetch is a 5, and we will copy 7 values (from the 5 plus two) from 8 back (from the 7 in the offset table).
- BITS: 001 1011
- NIBBLE: 5
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 (5 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1 55
- REMAINING INPUT: b2 81 94 88 94 37 b8 00 55 55
We again get a 00 command, so we take the 5 from the nibble buffer (offset -2) and fetch a new nibble from the input to get 4 values to copy.
- BITS: 1 1011
- NIBBLE: b
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 (5 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1 55
- REMAINING INPUT: 81 94 88 94 37 b8 00 55 55
Another 110, we copy out 4 values.
- BITS: 11
- NIBBLE: b
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 81 94 88 94 (6 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 81 94 88 94
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1 55 81 94 88 94
- REMAINING INPUT: 37 b8 00 55 55
We fetch two bits, but need more for the command, so we refill the bit buffer mid-command and keep reading.
- BITS: (11) 1011 1000 0011 0111
- NIBBLE: b
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 81 94 88 94 (6 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 81 94 88 94
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1 55 81 94 88 94 37 b8
- REMAINING INPUT: 00 55 55
We find a 1110, we fetch a nibble to find out what it wants us to do. This time it's 0xb or 1011 in binary.
- BITS: 11 1000 0011 0111
- NIBBLE: b
- BACKBUFFER: 01 01 01 01 e0 e0 e0 e0 e3 e3 e2 e2 61 61 a1 21 b5 b5 ab a1 81 94 88 94 (6 entries)
- OUTPUT: 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e3 e3 e2 e2 61 61 a1 21 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 b5 b5 ab a1 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 e0 e0 e0 e0 01 01 01 01 81 94 88 94 00 55 88 55
- CONSUMED INPUT: d8 d8 01 01 01 01 e0 e0 e0 e0 55 e3 e3 e2 e2 61 61 a1 21 47 70 46 b5 b5 ab a1 55 81 94 88 94 37 b8 00 55 55
- REMAINING INPUT:
We're done (with this part).
Verification by BlackStar:
Using the Dosbox debugger, a breakpoint was set the moment the pixel data for the first few lines was sent to videomemory. Data segment at point of inspection:
0FB7:0000 CB 00 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0010 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0020 E0 E0 01 01 01 01 E3 E3 E2 E2 61 61 A1 21 E0 E0 0FB7:0030 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0040 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0050 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0060 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0070 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0080 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0090 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:00A0 E0 E0 01 01 01 01 B5 B5 AB A1 01 01 01 01 E0 E0 0FB7:00B0 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:00C0 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:00D0 E0 E0 01 01 01 01 81 94 88 94 00 55 88 55 00 D5 0FB7:00E0 88 D5 00 55 88 55 00 55 88 55 00 55 88 55 00 55 0FB7:00F0 88 55 01 41 81 41 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0100 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0110 E0 E0 01 01 01 01 E0 E0 E0 E0 01 01 01 01 E0 E0 0FB7:0120 E0 E0 01 01 01 01 E0 E0 E0 E0 00 00 00 00 00 00 0FB7:0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0FB7:01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00