12 * The Cochran file format is designed to be annoying to read. It's roughly:
14 * 0x00000: room for 65534 4-byte words, giving the starting offsets
15 * of the dives themselves.
17 * 0x3fff8: the size of the file + 1
18 * 0x3ffff: 0 (high 32 bits of filesize? Bogus: the offsets into the file
19 * are 32-bit, so it can't be a large file anyway)
21 * 0x40000: "block 0": the decoding block. The first byte is some random
22 * value (0x46 in the files I have access to), the next 200+ bytes or so
23 * are the "scrambling array" that needs to be added into the file
24 * contents to make sense of them.
26 * The descrambling array seems to be of some random size which is likely
27 * determinable from the array somehow, the two test files I have it as
28 * 230 bytes and 234 bytes respectively.
30 static unsigned int partial_decode(unsigned int start, unsigned int end,
31 const unsigned char *decode, unsigned offset, unsigned mod,
32 const unsigned char *buf, unsigned int size, unsigned char *dst)
36 for (i = start ; i < end; i++) {
37 unsigned char d = decode[offset++];
51 * The decode buffer size can be figured out by simply trying our the
52 * decode: we expect that the scrambled contents are largely random, and
53 * thus tend to have half the bits set. Summing over the bytes is going
54 * to give an average of 0x80 per byte.
56 * The decoded array is mostly full of zeroes, so the sum is lower.
60 static int figure_out_modulus(const unsigned char *decode, const unsigned char *dive, unsigned int size)
63 unsigned int min = ~0u;
68 for (mod = 50; mod < 300; mod++) {
71 sum = partial_decode(0, 0x0fff, decode, 1, mod, dive, size, NULL);
80 #define hexchar(n) ("0123456789abcdef"[(n)&15])
82 static int show_line(unsigned offset, const unsigned char *data, unsigned size, int show_empty)
92 memset(buffer, ' ', sizeof(buffer));
93 off = sprintf(buffer, "%06x ", offset);
94 for (i = 0; i < size; i++) {
95 char *hex = buffer + off + 3*i;
96 char *asc = buffer + off + 50 + i;
97 unsigned char byte = data[i];
99 hex[0] = hexchar(byte>>4);
100 hex[1] = hexchar(byte);
102 if (byte < 32 || byte > 126)
117 static void cochran_debug_write(const char *filename, const unsigned char *data, unsigned size)
121 for (i = 0; i < size; i += 16)
122 show = show_line(i, data + i, size - i, show);
125 static void parse_cochran_header(const char *filename,
126 const unsigned char *decode, unsigned mod,
127 const unsigned char *in, unsigned size)
129 char *buf = malloc(size);
131 /* Do the "null decode" using a one-byte decode array of '\0' */
132 partial_decode(0 , 0x0b14, "", 0, 1, in, size, buf);
135 * The header scrambling is different form the dive
136 * scrambling. Oh yay!
139 partial_decode(0x058c, 0x0b14, decode, 0, mod, in, size, buf);
141 partial_decode(0x05a0, 0x0b14, decode, 0, mod, in, size, buf);
143 partial_decode(0x0b14, 0x1b14, decode, 0, mod, in, size, buf);
144 partial_decode(0x1b14, 0x2b14, decode, 0, mod, in, size, buf);
145 partial_decode(0x2b14, 0x3b14, decode, 0, mod, in, size, buf);
146 partial_decode(0x3b14, 0x5414, decode, 0, mod, in, size, buf);
147 partial_decode(0x5414, size, decode, 0, mod, in, size, buf);
149 printf("\n%s, header\n\n", filename);
150 cochran_debug_write(filename, buf, size);
155 static void parse_cochran_dive(const char *filename, int dive,
156 const unsigned char *decode, unsigned mod,
157 const unsigned char *in, unsigned size)
159 char *buf = malloc(size);
162 * The scrambling has odd boundaries. I think the boundaries
163 * match some data structure size, but I don't know. They were
164 * discovered the same way we dynamically discover the decode
165 * size: automatically looking for least random output.
167 * The boundaries are also this confused "off-by-one" thing,
168 * the same way the file size is off by one. It's as if the
169 * cochran software forgot to write one byte at the beginning.
171 partial_decode(0 , 0x0fff, decode, 1, mod, in, size, buf);
172 partial_decode(0x0fff, 0x1fff, decode, 0, mod, in, size, buf);
173 partial_decode(0x1fff, 0x2fff, decode, 0, mod, in, size, buf);
174 partial_decode(0x2fff, 0x48ff, decode, 0, mod, in, size, buf);
177 * This is not all the descrambling you need - the above are just
178 * what appears to be the fixed-size blocks. The rest is also
179 * scrambled, but there seems to be size differences in the data,
180 * so this just descrambles part of it:
182 partial_decode(0x48ff, 0x4a14, decode, 0, mod, in, size, buf);
183 partial_decode(0x4a14, 0xc9bd, decode, 0, mod, in, size, buf);
184 partial_decode(0xc9bd, size, decode, 0, mod, in, size, buf);
186 printf("\n%s, dive %d\n\n", filename, dive);
187 cochran_debug_write(filename, buf, size);
192 int try_to_open_cochran(const char *filename, struct memblock *mem, GError **error)
196 unsigned int *offsets, dive1, dive2;
197 unsigned char *decode = mem->buffer + 0x40001;
199 if (mem->size < 0x40000)
201 offsets = mem->buffer;
204 if (dive1 < 0x40000 || dive2 < dive1 || dive2 > mem->size)
207 mod = figure_out_modulus(decode, mem->buffer + dive1, dive2 - dive1);
209 parse_cochran_header(filename, decode, mod, mem->buffer + 0x40000, dive1 - 0x40000);
211 for (i = 0; i < 65534; i++) {
213 dive2 = offsets[i+1];
216 if (dive2 > mem->size)
218 parse_cochran_dive(filename, i+1, decode, mod, mem->buffer + dive1, dive2 - dive1);