1 |
/* |
2 |
Raw Photo Parser |
3 |
Copyright 2004-2006 by Dave Coffin, dcoffin a cybercom o net |
4 |
|
5 |
This program displays raw metadata for all raw photo formats. |
6 |
It is free for all uses. |
7 |
|
8 |
$Revision: 1.66 $ |
9 |
$Date: 2008/01/19 06:01:47 $ |
10 |
*/ |
11 |
|
12 |
#include <stdio.h> |
13 |
#include <string.h> |
14 |
#include <stdlib.h> |
15 |
#include <ctype.h> |
16 |
|
17 |
#ifdef WIN32 |
18 |
#include <winsock2.h> |
19 |
typedef __int64 INT64; |
20 |
#else |
21 |
#include <netinet/in.h> |
22 |
typedef long long INT64; |
23 |
#endif |
24 |
|
25 |
/* |
26 |
TIFF and CIFF data blocks can be quite large. |
27 |
Display only the first DLEN bytes. |
28 |
*/ |
29 |
#ifndef DLEN |
30 |
#define DLEN 768 |
31 |
#endif |
32 |
|
33 |
#define ushort UshORt |
34 |
typedef unsigned char uchar; |
35 |
typedef unsigned short ushort; |
36 |
|
37 |
FILE *ifp; |
38 |
short order; |
39 |
char *fname, make[128], model[128], model2[128]; |
40 |
int is_dng; |
41 |
|
42 |
ushort sget2 (uchar *s) |
43 |
{ |
44 |
if (order == 0x4949) /* "II" means little-endian */ |
45 |
return s[0] | s[1] << 8; |
46 |
else /* "MM" means big-endian */ |
47 |
return s[0] << 8 | s[1]; |
48 |
} |
49 |
#define sget2(s) sget2((uchar *)s) |
50 |
|
51 |
ushort get2() |
52 |
{ |
53 |
uchar str[2] = { 0xff,0xff }; |
54 |
fread (str, 1, 2, ifp); |
55 |
return sget2(str); |
56 |
} |
57 |
|
58 |
int sget4 (uchar *s) |
59 |
{ |
60 |
if (order == 0x4949) |
61 |
return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; |
62 |
else |
63 |
return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; |
64 |
} |
65 |
#define sget4(s) sget4((uchar *)s) |
66 |
|
67 |
int get4() |
68 |
{ |
69 |
uchar str[4] = { 0xff,0xff,0xff,0xff }; |
70 |
fread (str, 1, 4, ifp); |
71 |
return sget4(str); |
72 |
} |
73 |
|
74 |
float int_to_float (int i) |
75 |
{ |
76 |
union { int i; float f; } u; |
77 |
u.i = i; |
78 |
return u.f; |
79 |
} |
80 |
|
81 |
double get_double() |
82 |
{ |
83 |
union { char c[8]; double d; } u; |
84 |
int i, rev; |
85 |
|
86 |
rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); |
87 |
for (i=0; i < 8; i++) |
88 |
u.c[i ^ rev] = fgetc(ifp); |
89 |
return u.d; |
90 |
} |
91 |
|
92 |
void tiff_dump(int base, int tag, int type, int count, int level) |
93 |
{ |
94 |
int save, j, num, den; |
95 |
uchar c; |
96 |
int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; |
97 |
|
98 |
if (count * size[type < 13 ? type:0] > 4) |
99 |
fseek (ifp, get4()+base, SEEK_SET); |
100 |
save = ftell(ifp); |
101 |
printf("%*stag=0x%x %d, type=%d, count=%d, offset=%06x, data=", |
102 |
level*2, "", tag, tag, type, count, save); |
103 |
if (tag == 34310) goto quit; |
104 |
if (type==2) putchar('\"'); |
105 |
for (j = 0; j < count && j < DLEN; j++) |
106 |
switch (type) { |
107 |
case 1: case 6: case 7: /* byte values */ |
108 |
printf ("%c%02x",(j & 31) || count < 17 ? ' ':'\n', fgetc(ifp) & 0xff); |
109 |
break; |
110 |
case 2: /* null-terminated ASCII strings */ |
111 |
c = fgetc(ifp); |
112 |
putchar(isprint(c) ? c:'.'); |
113 |
break; |
114 |
case 3: case 8: /* word values */ |
115 |
printf ("%c%04x",(j & 15) || count < 9 ? ' ':'\n', get2()); |
116 |
break; |
117 |
case 4: case 9: /* dword values */ |
118 |
printf ("%c%08x",(j & 7) || count < 5 ? ' ':'\n', get4()); |
119 |
break; |
120 |
case 5: case 10: /* rationals */ |
121 |
num = get4(); |
122 |
den = get4(); |
123 |
printf (" %d/%d", num, den); |
124 |
// printf (" %lf", (double) num/den); |
125 |
break; |
126 |
} |
127 |
if (type==2) putchar('\"'); |
128 |
quit: |
129 |
putchar('\n'); |
130 |
fseek (ifp, save, SEEK_SET); |
131 |
} |
132 |
|
133 |
void parse_nikon_capture_note (int length) |
134 |
{ |
135 |
unsigned sorder, offset, tag, j, size; |
136 |
|
137 |
puts (" Nikon Capture Note:"); |
138 |
sorder = order; |
139 |
order = 0x4949; |
140 |
fseek (ifp, 22, SEEK_CUR); |
141 |
for (offset=22; offset+22 < length; offset += 22+size) { |
142 |
tag = get4(); |
143 |
fseek (ifp, 14, SEEK_CUR); |
144 |
size = get4()-4; |
145 |
printf(" tag=0x%08x, size=%d", tag, size); |
146 |
for (j=0; j < size; j++) |
147 |
printf ("%s%02x", j & 31 ? " ":"\n\t", fgetc(ifp)); |
148 |
puts(""); |
149 |
} |
150 |
order = sorder; |
151 |
} |
152 |
|
153 |
void nikon_decrypt (uchar ci, uchar cj, int tag, int i, int size, uchar *buf) |
154 |
{ |
155 |
static const uchar xlat[2][256] = { |
156 |
{ 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, |
157 |
0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, |
158 |
0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, |
159 |
0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, |
160 |
0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, |
161 |
0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, |
162 |
0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, |
163 |
0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, |
164 |
0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, |
165 |
0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, |
166 |
0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, |
167 |
0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, |
168 |
0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, |
169 |
0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, |
170 |
0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, |
171 |
0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, |
172 |
{ 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, |
173 |
0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, |
174 |
0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, |
175 |
0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, |
176 |
0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, |
177 |
0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, |
178 |
0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, |
179 |
0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, |
180 |
0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, |
181 |
0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, |
182 |
0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, |
183 |
0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, |
184 |
0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, |
185 |
0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, |
186 |
0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, |
187 |
0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; |
188 |
uchar ck=0x60; |
189 |
|
190 |
if (strncmp ((char *)buf, "02", 2)) return; |
191 |
ci = xlat[0][ci]; |
192 |
cj = xlat[1][cj]; |
193 |
printf("Decrypted tag 0x%x:\n%*s", tag, (i & 31)*3, ""); |
194 |
for (; i < size; i++) |
195 |
printf("%02x%c", buf[i] ^ (cj += ci * ck++), (i & 31) == 31 ? '\n':' '); |
196 |
if (size & 31) puts(""); |
197 |
} |
198 |
|
199 |
int parse_tiff_ifd (int base, int level); |
200 |
|
201 |
void parse_makernote (int base, int level) |
202 |
{ |
203 |
int offset=0, entries, tag, type, count, val, save; |
204 |
unsigned serial=0, key=0; |
205 |
uchar buf91[630]="", buf97[608]="", buf98[31]=""; |
206 |
short sorder; |
207 |
char buf[10]; |
208 |
|
209 |
/* |
210 |
The MakerNote might have its own TIFF header (possibly with |
211 |
its own byte-order!), or it might just be a table. |
212 |
*/ |
213 |
sorder = order; |
214 |
fread (buf, 1, 10, ifp); |
215 |
if (!strcmp (buf,"Nikon")) { /* starts with "Nikon\0\2\0\0\0" ? */ |
216 |
base = ftell(ifp); |
217 |
order = get2(); /* might differ from file-wide byteorder */ |
218 |
val = get2(); /* should be 42 decimal */ |
219 |
offset = get4(); |
220 |
fseek (ifp, offset-8, SEEK_CUR); |
221 |
} else if (!strcmp (buf,"OLYMPUS")) { |
222 |
base = ftell(ifp)-10; |
223 |
fseek (ifp, -2, SEEK_CUR); |
224 |
order = get2(); |
225 |
val = get2(); |
226 |
} else if (!strncmp (buf,"FUJIFILM",8) || |
227 |
!strncmp (buf,"SONY",4) || |
228 |
!strcmp (buf,"Panasonic")) { |
229 |
order = 0x4949; |
230 |
fseek (ifp, 2, SEEK_CUR); |
231 |
} else if (!strcmp (buf,"OLYMP") || |
232 |
!strcmp (buf,"LEICA") || |
233 |
!strcmp (buf,"Ricoh") || |
234 |
!strcmp (buf,"EPSON")) |
235 |
fseek (ifp, -2, SEEK_CUR); |
236 |
else if (!strcmp (buf,"AOC")) |
237 |
fseek (ifp, -4, SEEK_CUR); |
238 |
else |
239 |
fseek (ifp, -10, SEEK_CUR); |
240 |
|
241 |
entries = get2(); |
242 |
if (entries > 100) return; |
243 |
puts(" MakerNote:"); |
244 |
while (entries--) { |
245 |
save = ftell(ifp); |
246 |
tag = get2(); |
247 |
type = get2(); |
248 |
count= get4(); |
249 |
tiff_dump (base, tag, type, count, level); |
250 |
if ((tag == 0x11 && !strncmp(make,"NIKON",5)) || type == 13) { |
251 |
fseek (ifp, get4()+base, SEEK_SET); |
252 |
parse_tiff_ifd (base, level+1); |
253 |
} |
254 |
if (tag == 0x1d) |
255 |
while ((val = fgetc(ifp)) && val != EOF) |
256 |
serial = serial*10 + (isdigit(val) ? val - '0' : val % 10); |
257 |
if (tag == 0x91) |
258 |
fread (buf91, sizeof buf91, 1, ifp); |
259 |
if (tag == 0x97) |
260 |
fread (buf97, sizeof buf97, 1, ifp); |
261 |
if (tag == 0x98) |
262 |
fread (buf98, sizeof buf98, 1, ifp); |
263 |
if (tag == 0xa7) |
264 |
key = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); |
265 |
if (!strcmp (buf,"OLYMP") && tag >> 8 == 0x20) |
266 |
parse_tiff_ifd (base, level+1); |
267 |
if (tag == 0xe01) |
268 |
parse_nikon_capture_note (count); |
269 |
if (tag == 0xb028) { |
270 |
fseek (ifp, get4(), SEEK_SET); |
271 |
parse_tiff_ifd (base, level+1); |
272 |
} |
273 |
fseek (ifp, save+12, SEEK_SET); |
274 |
} |
275 |
nikon_decrypt (serial, key, 0x91, 4, sizeof buf91, buf91); |
276 |
if (!strncmp ((char *)buf97, "0205", 4)) |
277 |
nikon_decrypt (serial, key, 0x97, 4, 284, buf97); |
278 |
else |
279 |
nikon_decrypt (serial, key, 0x97, 284, sizeof buf97, buf97); |
280 |
nikon_decrypt (serial, key, 0x98, 4, sizeof buf98, buf98); |
281 |
order = sorder; |
282 |
} |
283 |
|
284 |
void parse_exif (int base, int level) |
285 |
{ |
286 |
int entries, tag, type, count, save; |
287 |
|
288 |
puts("EXIF table:"); |
289 |
entries = get2(); |
290 |
while (entries--) { |
291 |
save = ftell(ifp); |
292 |
tag = get2(); |
293 |
type = get2(); |
294 |
count= get4(); |
295 |
tiff_dump (base, tag, type, count, level); |
296 |
if (tag == 0x927c) |
297 |
parse_makernote (base, level+1); |
298 |
fseek (ifp, save+12, SEEK_SET); |
299 |
} |
300 |
} |
301 |
|
302 |
void parse_mos(int level); |
303 |
|
304 |
void sony_decrypt (unsigned *data, int len, int start, int key) |
305 |
{ |
306 |
static unsigned pad[128], p; |
307 |
|
308 |
if (start) { |
309 |
for (p=0; p < 4; p++) |
310 |
pad[p] = key = key * 48828125 + 1; |
311 |
pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; |
312 |
for (p=4; p < 127; p++) |
313 |
pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; |
314 |
for (p=0; p < 127; p++) |
315 |
pad[p] = htonl(pad[p]); |
316 |
} |
317 |
while (len--) |
318 |
*data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; |
319 |
} |
320 |
|
321 |
int parse_tiff_ifd (int base, int level) |
322 |
{ |
323 |
int entries, tag, type, count, slen, save, save2, i; |
324 |
unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; |
325 |
FILE *sfp; |
326 |
|
327 |
entries = get2(); |
328 |
if (entries > 1024) return 1; |
329 |
while (entries--) { |
330 |
save = ftell(ifp); |
331 |
tag = get2(); |
332 |
type = get2(); |
333 |
count= get4(); |
334 |
slen = count; |
335 |
if (slen > 128) slen = 128; |
336 |
tiff_dump (base, tag, type, count, level); |
337 |
switch (tag) { |
338 |
case 0x10f: /* Make tag */ |
339 |
fgets (make, slen, ifp); |
340 |
break; |
341 |
case 0x110: /* Model tag */ |
342 |
fgets (model, slen, ifp); |
343 |
break; |
344 |
case 33405: /* Model2 tag */ |
345 |
fgets (model2, slen, ifp); |
346 |
break; |
347 |
case 0x14a: /* SubIFD tag */ |
348 |
save2 = ftell(ifp); |
349 |
for (i=0; i < count; i++) { |
350 |
printf ("SubIFD #%d:\n", i+1); |
351 |
fseek (ifp, save2 + i*4, SEEK_SET); |
352 |
fseek (ifp, get4()+base, SEEK_SET); |
353 |
parse_tiff_ifd (base, level+1); |
354 |
} |
355 |
break; |
356 |
case 29184: sony_offset = get4(); break; |
357 |
case 29185: sony_length = get4(); break; |
358 |
case 29217: sony_key = get4(); break; |
359 |
case 33424: |
360 |
puts("Kodak private data:"); |
361 |
fseek (ifp, get4()+base, SEEK_SET); |
362 |
parse_tiff_ifd (base, level+1); |
363 |
break; |
364 |
case 34310: |
365 |
parse_mos(0); |
366 |
break; |
367 |
case 34665: |
368 |
fseek (ifp, get4()+base, SEEK_SET); |
369 |
parse_exif (base, level+1); |
370 |
break; |
371 |
case 34853: |
372 |
puts("GPS data:"); |
373 |
fseek (ifp, get4()+base, SEEK_SET); |
374 |
parse_tiff_ifd (base, level+1); |
375 |
break; |
376 |
case 50459: |
377 |
i = order; |
378 |
save2 = ftell(ifp); |
379 |
order = get2(); |
380 |
fseek (ifp, save2 + (get2(),get4()), SEEK_SET); |
381 |
parse_tiff_ifd (save2, level+1); |
382 |
order = i; |
383 |
break; |
384 |
case 50706: |
385 |
is_dng = 1; |
386 |
break; |
387 |
case 50740: |
388 |
if (count != 4 || type != 1) break; |
389 |
puts("Sony SR2 private IFD:"); |
390 |
fseek (ifp, get4()+base, SEEK_SET); |
391 |
parse_tiff_ifd (base, level+1); |
392 |
} |
393 |
fseek (ifp, save+12, SEEK_SET); |
394 |
} |
395 |
if (sony_length && (buf = malloc(sony_length))) { |
396 |
fseek (ifp, sony_offset, SEEK_SET); |
397 |
fread (buf, sony_length, 1, ifp); |
398 |
sony_decrypt (buf, sony_length/4, 1, sony_key); |
399 |
sfp = ifp; |
400 |
if ((ifp = tmpfile())) { |
401 |
fwrite (buf, sony_length, 1, ifp); |
402 |
fseek (ifp, 0, SEEK_SET); |
403 |
puts ("Sony SR2 encrypted IFD:"); |
404 |
parse_tiff_ifd (-sony_offset, level); |
405 |
fclose (ifp); |
406 |
} |
407 |
ifp = sfp; |
408 |
free (buf); |
409 |
} |
410 |
return 0; |
411 |
} |
412 |
|
413 |
/* |
414 |
Parse a TIFF file looking for camera model and decompress offsets. |
415 |
*/ |
416 |
void parse_tiff (int base) |
417 |
{ |
418 |
int doff, ifd=0; |
419 |
|
420 |
fseek (ifp, base, SEEK_SET); |
421 |
order = get2(); |
422 |
if (order != 0x4949 && order != 0x4d4d) return; |
423 |
get2(); |
424 |
while ((doff = get4())) { |
425 |
fseek (ifp, doff+base, SEEK_SET); |
426 |
printf ("IFD #%d:\n", ifd++); |
427 |
if (parse_tiff_ifd (base, 0)) break; |
428 |
} |
429 |
} |
430 |
|
431 |
void parse_minolta() |
432 |
{ |
433 |
int data_offset, save, tag, len; |
434 |
|
435 |
fseek (ifp, 4, SEEK_SET); |
436 |
data_offset = get4() + 8; |
437 |
while ((save=ftell(ifp)) < data_offset) { |
438 |
tag = get4(); |
439 |
len = get4(); |
440 |
printf ("Tag %c%c%c offset %06x length %06x\n", |
441 |
tag>>16, tag>>8, tag, save, len); |
442 |
switch (tag) { |
443 |
case 0x545457: /* TTW */ |
444 |
parse_tiff (ftell(ifp)); |
445 |
} |
446 |
fseek (ifp, save+len+8, SEEK_SET); |
447 |
} |
448 |
} |
449 |
|
450 |
/* |
451 |
Parse the CIFF structure. |
452 |
*/ |
453 |
void parse_ciff (int offset, int length, int level) |
454 |
{ |
455 |
int tboff, nrecs, i, j, type, len, dlen, roff, aoff=0, save; |
456 |
char c, name[256]; |
457 |
ushort key[2]; |
458 |
|
459 |
fseek (ifp, offset+length-4, SEEK_SET); |
460 |
tboff = get4() + offset; |
461 |
fseek (ifp, tboff, SEEK_SET); |
462 |
nrecs = get2(); |
463 |
if (nrecs > 100) return; |
464 |
printf ("%*s%d records:\n", level*2, "", nrecs); |
465 |
for (i = 0; i < nrecs; i++) { |
466 |
save = ftell(ifp); |
467 |
type = get2(); |
468 |
printf ("%*stype=0x%04x", level*2, "", type); |
469 |
if (type & 0x4000) { |
470 |
len = 8; |
471 |
type &= 0x3fff; |
472 |
} else { |
473 |
len = get4(); |
474 |
roff = get4(); |
475 |
aoff = offset + roff; |
476 |
printf (", length=%d, reloff=%d, absoff=%d", |
477 |
len, roff, aoff); |
478 |
fseek (ifp, aoff, SEEK_SET); |
479 |
} |
480 |
if ((type & 0xe700) == 0) |
481 |
printf (", data="); |
482 |
if (type == 0x0032) /* display as words */ |
483 |
type |= 0x1000; |
484 |
dlen = len < DLEN ? len:DLEN; |
485 |
switch (type >> 8) { |
486 |
case 0x28: |
487 |
case 0x30: |
488 |
putchar('\n'); |
489 |
parse_ciff (aoff, len, level+1); |
490 |
fseek (ifp, save+10, SEEK_SET); |
491 |
continue; |
492 |
case 0x00: /* byte values */ |
493 |
for (j = 0; j < dlen; j++) |
494 |
printf ("%c%02x",(j & 31) || dlen < 16 ? ' ':'\n', fgetc(ifp) & 0xff); |
495 |
break; |
496 |
case 0x08: /* null-terminated ASCII strings */ |
497 |
putchar('\"'); |
498 |
for (j = 0; j < dlen; j++) { |
499 |
c = fgetc(ifp); |
500 |
putchar( isprint(c) ? c:'.'); |
501 |
} |
502 |
putchar('\"'); |
503 |
break; |
504 |
case 0x10: /* word values */ |
505 |
key[0] = get2(); |
506 |
fseek (ifp, -2, SEEK_CUR); |
507 |
if (type == 0x1032 && key[0] == 1040) |
508 |
key[1] = 17907; |
509 |
else key[0] = key[1] = 0; |
510 |
for (j = 0; j < dlen; j+=2) |
511 |
printf ("%c%5u",(j & 31) || dlen < 16 ? ' ':'\n', |
512 |
get2() ^ key[(j >> 1) & 1]); |
513 |
break; |
514 |
case 0x18: /* dword values */ |
515 |
for (j = 0; j < dlen; j+=4) |
516 |
printf ("%c%08x",(j & 31) || dlen < 16 ? ' ':'\n', get4()); |
517 |
} |
518 |
putchar('\n'); |
519 |
fseek (ifp, save+10, SEEK_SET); |
520 |
if (type == 0x080a) { /* Get the camera name */ |
521 |
fseek (ifp, aoff, SEEK_SET); |
522 |
fread (name, 256, 1, ifp); |
523 |
strcpy (make, name); |
524 |
strcpy (model, name + strlen(make)+1); |
525 |
} |
526 |
} |
527 |
} |
528 |
|
529 |
int parse_jpeg (int offset) |
530 |
{ |
531 |
int len, save, hlen; |
532 |
|
533 |
fseek (ifp, offset, SEEK_SET); |
534 |
if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; |
535 |
|
536 |
while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) { |
537 |
order = 0x4d4d; |
538 |
len = get2() - 2; |
539 |
save = ftell(ifp); |
540 |
order = get2(); |
541 |
hlen = get4(); |
542 |
if (get4() == 0x48454150) /* "HEAP" */ |
543 |
parse_ciff (save+hlen, len-hlen, 0); |
544 |
parse_tiff (save+6); |
545 |
fseek (ifp, save+len, SEEK_SET); |
546 |
} |
547 |
return 1; |
548 |
} |
549 |
|
550 |
void parse_riff (int level) |
551 |
{ |
552 |
unsigned i, size, end, save; |
553 |
char tag[4], type[4], buf[64]; |
554 |
|
555 |
order = 0x4949; |
556 |
fread (tag, 4, 1, ifp); |
557 |
size = get4(); |
558 |
if (isdigit(tag[0])) { |
559 |
fseek (ifp, size, SEEK_CUR); |
560 |
return; |
561 |
} |
562 |
printf ("%*.4s size %d", level*4+4, tag, size); |
563 |
if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { |
564 |
end = ftell(ifp) + size; |
565 |
fread (type, 4, 1, ifp); |
566 |
printf (" type %.4s:\n", type); |
567 |
while (ftell(ifp) < end) |
568 |
parse_riff (level+1); |
569 |
} else { |
570 |
save = ftell(ifp); |
571 |
fread (buf, 1, 40, ifp); |
572 |
printf (": "); |
573 |
for (i=0; i < 40 && isprint(buf[i]); i++) |
574 |
putchar (buf[i]); |
575 |
putchar ('\n'); |
576 |
fseek (ifp, save+size, SEEK_SET); |
577 |
} |
578 |
} |
579 |
|
580 |
void parse_mos(int level) |
581 |
{ |
582 |
char data[256]; |
583 |
int i, skip, save; |
584 |
char *cp; |
585 |
|
586 |
save = ftell(ifp); |
587 |
while (1) { |
588 |
if (get4() != 0x504b5453) break; |
589 |
get4(); |
590 |
printf ("%*sPKTS ", level, ""); |
591 |
fread (data, 1, 40, ifp); |
592 |
skip = get4(); |
593 |
printf ("%s %d bytes: ", data, skip); |
594 |
if (!strcmp(data,"pattern_ratation_angle")) { |
595 |
printf ("%d\n", get2()); |
596 |
continue; |
597 |
} |
598 |
if (!strcmp(data,"icc_camera_to_tone_matrix")) { |
599 |
for (i=0; i < skip/4; i++) |
600 |
printf ("%f ", int_to_float(get4())); |
601 |
putchar('\n'); |
602 |
continue; |
603 |
} |
604 |
fread (data, 1, sizeof data, ifp); |
605 |
fseek (ifp, -sizeof data, SEEK_CUR); |
606 |
data[sizeof data - 1] = 0; |
607 |
while ((cp=strchr(data,'\n'))) |
608 |
*cp = ' '; |
609 |
printf ("%s\n",data); |
610 |
parse_mos(level+2); |
611 |
fseek (ifp, skip, SEEK_CUR); |
612 |
} |
613 |
fseek (ifp, save, SEEK_SET); |
614 |
} |
615 |
|
616 |
void parse_rollei() |
617 |
{ |
618 |
char line[128], *val; |
619 |
|
620 |
fseek (ifp, 0, SEEK_SET); |
621 |
do { |
622 |
fgets (line, 128, ifp); |
623 |
fputs (line, stdout); |
624 |
if ((val = strchr(line,'='))) |
625 |
*val++ = 0; |
626 |
else |
627 |
val = line + strlen(line); |
628 |
} while (strncmp(line,"EOHD",4)); |
629 |
strcpy (make, "Rollei"); |
630 |
strcpy (model, "d530flex"); |
631 |
} |
632 |
|
633 |
void get_utf8 (int offset, char *buf, int len) |
634 |
{ |
635 |
ushort c; |
636 |
char *cp; |
637 |
|
638 |
fseek (ifp, offset, SEEK_SET); |
639 |
for (cp=buf; (c = get2()) && cp+3 < buf+len; ) { |
640 |
if (c < 0x80) |
641 |
*cp++ = c; |
642 |
else if (c < 0x800) { |
643 |
*cp++ = 0xc0 + (c >> 6); |
644 |
*cp++ = 0x80 + (c & 0x3f); |
645 |
} else { |
646 |
*cp++ = 0xe0 + (c >> 12); |
647 |
*cp++ = 0x80 + (c >> 6 & 0x3f); |
648 |
*cp++ = 0x80 + (c & 0x3f); |
649 |
} |
650 |
} |
651 |
*cp = 0; |
652 |
} |
653 |
|
654 |
void parse_foveon() |
655 |
{ |
656 |
unsigned entries, off, len, tag, save, i, j, k, pent, poff[256][2]; |
657 |
char name[128], value[128], camf[0x20000], *pos, *cp, *dp; |
658 |
unsigned val, key, type, num, ndim, dim[3]; |
659 |
|
660 |
order = 0x4949; /* Little-endian */ |
661 |
fseek (ifp, -4, SEEK_END); |
662 |
fseek (ifp, get4(), SEEK_SET); |
663 |
if (get4() != 0x64434553) { /* SECd */ |
664 |
printf ("Bad Section identifier at %6x\n", (int)ftell(ifp)-4); |
665 |
return; |
666 |
} |
667 |
get4(); |
668 |
entries = get4(); |
669 |
while (entries--) { |
670 |
off = get4(); |
671 |
len = get4(); |
672 |
tag = get4(); |
673 |
save = ftell(ifp); |
674 |
fseek (ifp, off, SEEK_SET); |
675 |
printf ("%c%c%c%c at offset %06x, length %06x, ", |
676 |
tag, tag >> 8, tag >> 16, tag >> 24, off, len); |
677 |
if (get4() != (0x20434553 | (tag << 24))) { |
678 |
printf ("Bad Section identifier at %6x\n", off); |
679 |
return; |
680 |
} |
681 |
val = get4(); |
682 |
printf ("version %d.%d, ",val >> 16, val & 0xffff); |
683 |
switch (tag) { |
684 |
case 0x32414d49: /* IMA2 */ |
685 |
case 0x47414d49: /* IMAG */ |
686 |
printf ("type %d, " , get4()); |
687 |
printf ("format %2d, " , get4()); |
688 |
printf ("columns %4d, " , get4()); |
689 |
printf ("rows %4d, " , get4()); |
690 |
printf ("rowsize %d\n" , get4()); |
691 |
parse_jpeg (off+28); |
692 |
order = 0x4949; |
693 |
break; |
694 |
case 0x464d4143: /* CAMF */ |
695 |
printf ("type %d, ", get4()); |
696 |
get4(); |
697 |
for (i=0; i < 4; i++) |
698 |
putchar(fgetc(ifp)); |
699 |
val = get4(); |
700 |
printf (" version %d.%d:\n",val >> 16, val & 0xffff); |
701 |
key = get4(); |
702 |
if ((len -= 28) > 0x20000) |
703 |
len = 0x20000; |
704 |
fread (camf, 1, len, ifp); |
705 |
for (i=0; i < len; i++) { |
706 |
key = (key * 1597 + 51749) % 244944; |
707 |
val = key * (INT64) 301593171 >> 24; |
708 |
camf[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; |
709 |
} |
710 |
for (pos=camf; (unsigned) (pos-camf) < len; pos += sget4(pos+8)) { |
711 |
if (strncmp (pos, "CMb", 3)) { |
712 |
printf("Bad CAMF tag \"%.4s\"\n", pos); |
713 |
break; |
714 |
} |
715 |
val = sget4(pos+4); |
716 |
printf (" %4.4s version %d.%d: ", pos, val >> 16, val & 0xffff); |
717 |
switch (pos[3]) { |
718 |
case 'M': |
719 |
cp = pos + sget4(pos+16); |
720 |
type = sget4(cp); |
721 |
ndim = sget4(cp+4); |
722 |
dim[0] = dim[1] = dim[2] = 1; |
723 |
printf ("%d-dimensonal array %s of type %d:\n Key: (", |
724 |
ndim, pos+sget4(pos+12), sget4(cp)); |
725 |
dp = pos + sget4(cp+8); |
726 |
for (i=ndim; i--; ) { |
727 |
cp += 12; |
728 |
dim[i] = sget4(cp); |
729 |
printf ("%s %d%s", pos+sget4(cp+4), dim[i], i ? ", ":")\n"); |
730 |
} |
731 |
for (i=0; i < dim[2]; i++) { |
732 |
for (j=0; j < dim[1]; j++) { |
733 |
printf (" "); |
734 |
for (k=0; k < dim[0]; k++) |
735 |
switch (type) { |
736 |
case 5: |
737 |
printf ("%7d", *(uchar *)dp++); |
738 |
break; |
739 |
case 0: |
740 |
case 6: |
741 |
printf ("%7d", (short) sget2(dp)); |
742 |
dp += 2; |
743 |
break; |
744 |
case 1: |
745 |
case 2: |
746 |
printf (" %d", sget4(dp)); |
747 |
dp += 4; |
748 |
break; |
749 |
case 3: |
750 |
val = sget4(dp); |
751 |
printf (" %9f", int_to_float(val)); |
752 |
dp += 4; |
753 |
} |
754 |
printf ("\n"); |
755 |
} |
756 |
printf ("\n"); |
757 |
} |
758 |
break; |
759 |
case 'P': |
760 |
val = sget4(pos+16); |
761 |
num = sget4(pos+val); |
762 |
printf ("%s, %d parameters:\n", pos+sget4(pos+12), num); |
763 |
cp = pos+val+8 + num*8; |
764 |
for (i=0; i < num; i++) { |
765 |
val += 8; |
766 |
printf (" %s = %s\n", cp+sget4(pos+val), cp+sget4(pos+val+4)); |
767 |
} |
768 |
break; |
769 |
case 'T': |
770 |
cp = pos + sget4(pos+16); |
771 |
printf ("%s = %.*s\n", pos+sget4(pos+12), sget4(cp), cp+4); |
772 |
break; |
773 |
default: |
774 |
printf ("\n"); |
775 |
} |
776 |
} |
777 |
break; |
778 |
case 0x504f5250: /* PROP */ |
779 |
printf ("entries %d, ", pent=get4()); |
780 |
printf ("charset %d, ", get4()); |
781 |
get4(); |
782 |
printf ("nchars %d\n", get4()); |
783 |
off += pent*8 + 24; |
784 |
if ((unsigned) pent > 256) pent=256; |
785 |
for (i=0; i < pent*2; i++) |
786 |
poff[0][i] = off + get4()*2; |
787 |
for (i=0; i < pent; i++) { |
788 |
get_utf8 (poff[i][0], name, 128); |
789 |
get_utf8 (poff[i][1], value, 128); |
790 |
printf (" %s = %s\n", name, value); |
791 |
if (!strcmp (name,"CAMMANUF")) |
792 |
strcpy (make, value); |
793 |
if (!strcmp (name,"CAMMODEL")) |
794 |
strcpy (model, value); |
795 |
} |
796 |
} |
797 |
fseek (ifp, save, SEEK_SET); |
798 |
} |
799 |
} |
800 |
|
801 |
void parse_fuji (int offset) |
802 |
{ |
803 |
int entries, tag, len; |
804 |
|
805 |
fseek (ifp, offset, SEEK_SET); |
806 |
if (!(len = get4())) return; |
807 |
printf ("Fuji table at %d:\n",len); |
808 |
fseek (ifp, len, SEEK_SET); |
809 |
entries = get4(); |
810 |
if (entries > 255) return; |
811 |
while (entries--) { |
812 |
tag = get2(); |
813 |
len = get2(); |
814 |
printf ("Fuji tag=0x%x, len=%d, data =",tag,len); |
815 |
while (len--) |
816 |
printf (" %02x",fgetc(ifp)); |
817 |
putchar ('\n'); |
818 |
} |
819 |
} |
820 |
|
821 |
void parse_phase_one (int base) |
822 |
{ |
823 |
unsigned entries, tag, type, len, data, save; |
824 |
unsigned meta=0, wide=0, high=0, i, j; |
825 |
char str[256]; |
826 |
|
827 |
fseek (ifp, base, SEEK_SET); |
828 |
order = get4() & 0xffff; |
829 |
if (get4() >> 8 != 0x526177) return; |
830 |
fseek (ifp, base+get4(), SEEK_SET); |
831 |
entries = get4(); |
832 |
get4(); |
833 |
while (entries--) { |
834 |
tag = get4(); |
835 |
type = get4(); |
836 |
len = get4(); |
837 |
data = get4(); |
838 |
save = ftell(ifp); |
839 |
printf ("Phase One tag=0x%x, type=%d, len=%2d, data = 0x%x", |
840 |
tag, type, len, data); |
841 |
if (type == 4 && len == 4 && data > 0xfffffff) |
842 |
printf (" = %f", int_to_float(data)); |
843 |
putchar ('\n'); |
844 |
if (tag == 0x110) meta = base+data; |
845 |
if (len > 4) |
846 |
fseek (ifp, base+data, SEEK_SET); |
847 |
if (type == 1 && len < 256) { |
848 |
fread (str, 256, 1, ifp); |
849 |
puts (str); |
850 |
} |
851 |
if (tag != 0x21c && type == 4 && len > 4) { |
852 |
for ( ; len > 0; len -= 4) |
853 |
printf ("%f ", int_to_float(get4())); |
854 |
puts (""); |
855 |
} |
856 |
fseek (ifp, save, SEEK_SET); |
857 |
} |
858 |
strcpy (make, "Phase One"); |
859 |
strcpy (model, "unknown"); |
860 |
if (!meta) return; |
861 |
fseek (ifp, meta, SEEK_SET); |
862 |
order = get2(); |
863 |
fseek (ifp, 6, SEEK_CUR); |
864 |
fseek (ifp, meta+get4(), SEEK_SET); |
865 |
entries = get4(); |
866 |
get4(); |
867 |
while (entries--) { |
868 |
tag = get4(); |
869 |
len = get4(); |
870 |
data = get4(); |
871 |
save = ftell(ifp); |
872 |
printf ("Phase One meta tag=0x%x, len=%2d, offset = 0x%x, data = ", |
873 |
tag, len, data); |
874 |
if (!((0x000801f4 >> (tag-0x400)) & 1)) putchar ('\n'); |
875 |
fseek (ifp, meta+data, SEEK_SET); |
876 |
switch (tag) { |
877 |
case 0x400: |
878 |
for (i=0; i < len; i+=2) |
879 |
printf ("%5u%c", get2(), (i & 6) == 6 || i == len-2 ? '\n':' '); |
880 |
break; |
881 |
case 0x401: |
882 |
for (i=0; i < 16; i+=2) |
883 |
printf ("%6u%c", get2(), (i & 14) == 14 || i == len-2 ? '\n':' '); |
884 |
for (; i < len; i+=4) |
885 |
printf ("%9.6f%c", int_to_float(get4()), |
886 |
(i & 28) == 12 || i == len-4 ? '\n':' '); |
887 |
break; |
888 |
case 0x402: |
889 |
printf ("%f\n", int_to_float (data)); |
890 |
break; |
891 |
case 0x404: case 0x405: case 0x406: case 0x407: |
892 |
fread (str, 256, 1, ifp); |
893 |
puts (str); |
894 |
break; |
895 |
case 0x408: case 0x413: |
896 |
printf ("%lf\n", get_double()); |
897 |
break; |
898 |
case 0x40b: case 0x410: case 0x416: |
899 |
for (i=0; i < len; i+=2) |
900 |
printf ("%6u%c", get2(), (i & 14) == 14 || i == len-2 ? '\n':' '); |
901 |
break; |
902 |
case 0x40f: case 0x418: case 0x419: case 0x41a: |
903 |
for (i=0; i < 4; i++) |
904 |
printf ("%02X%c", fgetc(ifp), i == 3 ? '\n':' '); |
905 |
for (; i < len; i+=4) |
906 |
printf ("%e%c", int_to_float(get4()), i == len-4 ? '\n':' '); |
907 |
break; |
908 |
case 0x412: |
909 |
for (i=0; i < 36; i+=4) { |
910 |
printf ("%u ", j=get4()); |
911 |
if (i == 4) wide = j; |
912 |
if (i == 12) high = j*2; |
913 |
} |
914 |
printf ("%u\n", get2()); |
915 |
for (i=0; i < wide*high; i++) |
916 |
printf ("%9.6f%c", int_to_float(get4()), |
917 |
i % wide == wide-1 ? '\n':' '); |
918 |
for (i=0; i < wide*high; i++) |
919 |
printf ("%5u%c", get2(), i % wide == wide-1 ? '\n':' '); |
920 |
break; |
921 |
default: |
922 |
for (i=0; i < len; i++) |
923 |
printf ("%02X%c", fgetc(ifp), |
924 |
(i & 15) == 15 || i == len-1 ? '\n':' '); |
925 |
} |
926 |
fseek (ifp, save, SEEK_SET); |
927 |
} |
928 |
} |
929 |
|
930 |
char *memmem (char *haystack, size_t haystacklen, |
931 |
char *needle, size_t needlelen) |
932 |
{ |
933 |
char *c; |
934 |
for (c = haystack; c <= haystack + haystacklen - needlelen; c++) |
935 |
if (!memcmp (c, needle, needlelen)) |
936 |
return c; |
937 |
return NULL; |
938 |
} |
939 |
|
940 |
/* |
941 |
Identify which camera created this file, and set global variables |
942 |
accordingly. Return nonzero if the file cannot be decoded. |
943 |
*/ |
944 |
void identify() |
945 |
{ |
946 |
char head[32], *cp; |
947 |
unsigned hlen, fsize, toff, tlen; |
948 |
|
949 |
make[0] = model[0] = model2[0] = is_dng = 0; |
950 |
order = get2(); |
951 |
hlen = get4(); |
952 |
fseek (ifp, 0, SEEK_SET); |
953 |
fread (head, 1, 32, ifp); |
954 |
fseek (ifp, 0, SEEK_END); |
955 |
fsize = ftell(ifp); |
956 |
if ((cp = memmem (head, 32, "MMMM", 4)) || |
957 |
(cp = memmem (head, 32, "IIII", 4))) { |
958 |
parse_phase_one (cp-head); |
959 |
if (cp-head) parse_tiff (0); |
960 |
} else if (order == 0x4949 || order == 0x4d4d) { |
961 |
if (!memcmp(head+6,"HEAPCCDR",8)) { |
962 |
parse_ciff (hlen, fsize - hlen, 0); |
963 |
fseek (ifp, hlen, SEEK_SET); |
964 |
} else |
965 |
parse_tiff (0); |
966 |
} else if (!memcmp (head,"NDF0",4)) { |
967 |
parse_tiff (12); |
968 |
} else if (!memcmp (head,"\0MRM",4)) { |
969 |
parse_minolta(); |
970 |
} else if (!memcmp (head,"FUJIFILM",8)) { |
971 |
fseek (ifp, 84, SEEK_SET); |
972 |
toff = get4(); |
973 |
tlen = get4(); |
974 |
parse_fuji (92); |
975 |
if (toff > 120) parse_fuji (120); |
976 |
parse_tiff (toff+12); |
977 |
} else if (!memcmp (head,"RIFF",4)) { |
978 |
fseek (ifp, 0, SEEK_SET); |
979 |
parse_riff(0); |
980 |
} else if (!memcmp (head,"DSC-Image",9)) |
981 |
parse_rollei(); |
982 |
else if (!memcmp (head,"FOVb",4)) |
983 |
parse_foveon(); |
984 |
parse_jpeg(0); |
985 |
} |
986 |
|
987 |
int main(int argc, char **argv) |
988 |
{ |
989 |
int arg; |
990 |
|
991 |
if (argc == 1) |
992 |
{ |
993 |
fprintf (stderr, |
994 |
"\nRaw Photo Parser" |
995 |
"\nby Dave Coffin, dcoffin a cybercom o net" |
996 |
"\n\nUsage: %s file1.crw file2.crw ...\n", argv[0]); |
997 |
return 1; |
998 |
} |
999 |
for (arg=1; arg < argc; arg++) |
1000 |
{ |
1001 |
fname = argv[arg]; |
1002 |
ifp = fopen (fname,"rb"); |
1003 |
if (!ifp) { |
1004 |
perror (fname); |
1005 |
continue; |
1006 |
} |
1007 |
printf ("\nParsing %s:\n", fname); |
1008 |
identify(); |
1009 |
fclose (ifp); |
1010 |
} |
1011 |
return 0; |
1012 |
} |