Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE
dcraw
parse.c
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File parse.c of Package dcraw
/* Raw Photo Parser Copyright 2004-2015 by Dave Coffin, dcoffin a cybercom o net This program displays raw metadata for all raw photo formats. It is free for all uses. $Revision: 1.78 $ $Date: 2018/06/01 21:26:34 $ */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #ifdef WIN32 #include <winsock2.h> typedef __int64 INT64; #else #include <netinet/in.h> typedef long long INT64; #endif /* TIFF and CIFF data blocks can be quite large. Display only the first DLEN bytes. */ #ifndef DLEN #define DLEN 768 #endif #define ushort UshORt typedef unsigned char uchar; typedef unsigned short ushort; FILE *ifp; short order; char *fname, make[128], model[128], model2[128]; int is_dng; ushort sget2 (uchar *s) { if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1]; } #define sget2(s) sget2((uchar *)s) ushort get2() { uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str); } int sget4 (uchar *s) { if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } #define sget4(s) sget4((uchar *)s) int get4() { uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str); } float int_to_float (int i) { union { int i; float f; } u; u.i = i; return u.f; } double get_double() { union { char c[8]; double d; } u; int i, rev; rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; } unsigned getbithuff (int nbits, const ushort *huff) { static unsigned bitbuf=0; static int vbits=0, reset=0; unsigned c; if (nbits == -1) return bitbuf = vbits = reset = 0; if (nbits == 0 || vbits < 0) return 0; while (vbits < nbits && (c = fgetc(ifp)) != EOF) { bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } c = bitbuf << (32-vbits) >> (32-nbits); if (huff) { vbits -= huff[c] >> 8; c = (uchar) huff[c]; } else vbits -= nbits; return c; } #define getbits(n) getbithuff(n,0) #define gethuff(h) getbithuff(*h,h+1) int ljpeg_diff (ushort *huff) { int len, diff; len = gethuff(huff); diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } void tiff_dump(int base, int tag, int type, int count, int level) { int save, j, num, den; uchar c; int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; if (count * size[type < 13 ? type:0] > 4) fseek (ifp, get4()+base, SEEK_SET); save = ftell(ifp); printf("%*stag=0x%x %d, type=%d, count=%d, offset=%06x, data=", level*2, "", tag, tag, type, count, save); if (tag == 34310) goto quit; if (type==2) putchar('\"'); for (j = 0; j < count && j < DLEN; j++) switch (type) { case 1: case 6: case 7: /* byte values */ printf ("%c%02x",(j & 31) || count < 17 ? ' ':'\n', fgetc(ifp) & 0xff); break; case 2: /* null-terminated ASCII strings */ c = fgetc(ifp); putchar(isprint(c) ? c:'.'); break; case 3: case 8: /* word values */ printf ("%c%04x",(j & 15) || count < 9 ? ' ':'\n', get2()); break; case 4: case 9: /* dword values */ printf ("%c%08x",(j & 7) || count < 5 ? ' ':'\n', get4()); break; case 5: case 10: /* rationals */ num = get4(); den = get4(); printf (" %d/%d", num, den); // printf (" %lf", (double) num/den); break; } if (type==2) putchar('\"'); quit: putchar('\n'); fseek (ifp, save, SEEK_SET); } void parse_nikon_capture_note (int length) { unsigned sorder, offset, tag, j, size; puts (" Nikon Capture Note:"); sorder = order; order = 0x4949; fseek (ifp, 22, SEEK_CUR); for (offset=22; offset+22 < length; offset += 22+size) { tag = get4(); fseek (ifp, 14, SEEK_CUR); size = get4()-4; printf(" tag=0x%08x, size=%d", tag, size); for (j=0; j < size; j++) printf ("%s%02x", j & 31 ? " ":"\n\t", fgetc(ifp)); puts(""); } order = sorder; } void nikon_decrypt (uchar ci, uchar cj, int tag, int i, int size, uchar *buf) { static const uchar xlat[2][256] = { { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; uchar ck=0x60; if (strncmp ((char *)buf, "02", 2)) return; ci = xlat[0][ci]; cj = xlat[1][cj]; printf("Decrypted tag 0x%x:\n%*s", tag, (i & 31)*3, ""); for (; i < size; i++) printf("%02x%c", buf[i] ^ (cj += ci * ck++), (i & 31) == 31 ? '\n':' '); if (size & 31) puts(""); } int parse_tiff_ifd (int base, int level); void parse_makernote (int base, int len, int level) { int offset=0, entries, tag, type, count, val, save; unsigned serial=0, key=0; uchar buf91[630]="", buf97[608]="", buf98[31]=""; short sorder; char buf[10]; /* The MakerNote might have its own TIFF header (possibly with its own byte-order!), or it might just be a table. */ sorder = order; fread (buf, 1, 10, ifp); if (!strcmp (buf,"Nikon")) { /* starts with "Nikon\0\2\0\0\0" ? */ base = ftell(ifp); order = get2(); /* might differ from file-wide byteorder */ val = get2(); /* should be 42 decimal */ offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS") || !strcmp (buf,"PENTAX ")) { base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp (buf,"SONY",4) || !strcmp (buf,"Panasonic")) { goto nf; } else if (!strncmp (buf,"FUJIFILM",8)) { base = ftell(ifp)-10; nf: order = 0x4949; fseek (ifp, 2, SEEK_CUR); } else if (!strcmp (buf,"OLYMP") || !strcmp (buf,"LEICA") || !strcmp (buf,"Ricoh") || !strcmp (buf,"EPSON")) fseek (ifp, -2, SEEK_CUR); else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); else { fseek (ifp, -10, SEEK_CUR); if (!strncmp(make,"SAMSUNG",7)) base = ftell(ifp); if (!strncmp (buf,"ev=",3)) { while (len--) putchar (fgetc(ifp)); putchar ('\n'); } } entries = get2(); if (entries > 127) return; printf ("%*sMakerNote:\n", level*2-2, ""); while (entries--) { save = ftell(ifp); tag = get2(); type = get2(); count= get4(); tiff_dump (base, tag, type, count, level); if ((tag == 0x11 && !strncmp(make,"NIKON",5)) || (tag >> 8 == 0x20 && !strncmp(buf ,"OLYMP",5)) || type == 13) { if (count == 1) fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base, level+1); } if (tag == 0x1d) while ((val = fgetc(ifp)) && val != EOF) serial = serial*10 + (isdigit(val) ? val - '0' : val % 10); if (tag == 0x91) fread (buf91, sizeof buf91, 1, ifp); if (tag == 0x97) fread (buf97, sizeof buf97, 1, ifp); if (tag == 0x98) fread (buf98, sizeof buf98, 1, ifp); if (tag == 0xa7) key = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp); if (tag == 0xe01) parse_nikon_capture_note (count); if (tag == 0xb028) { fseek (ifp, get4(), SEEK_SET); parse_tiff_ifd (base, level+1); } fseek (ifp, save+12, SEEK_SET); } nikon_decrypt (serial, key, 0x91, 4, sizeof buf91, buf91); if (!strncmp ((char *)buf97, "0205", 4)) nikon_decrypt (serial, key, 0x97, 4, 284, buf97); else nikon_decrypt (serial, key, 0x97, 284, sizeof buf97, buf97); nikon_decrypt (serial, key, 0x98, 4, sizeof buf98, buf98); order = sorder; } void parse_exif (int base, int level) { int entries, tag, type, count, save; printf ("%*sEXIF table:\n", level*2-2, ""); entries = get2(); while (entries--) { save = ftell(ifp); tag = get2(); type = get2(); count= get4(); tiff_dump (base, tag, type, count, level); if (tag == 0x927c) parse_makernote (base, count, level+1); fseek (ifp, save+12, SEEK_SET); } } void parse_mos(int level); void parse_minolta (int base); void parse_tiff (int base, int level); void parse_thumb (int base, int level) { int i=order; order = 0x4d4d; fseek (ifp, base, SEEK_SET); if (get4()==0xffd8ffe1 && get2() && get4()==0x45786966 && !get2()) { printf ("%*sEmbedded JPEG:\n", level*2, ""); parse_tiff (ftell(ifp), level+1); } order = i; } void sony_decrypt (unsigned *data, int len, int start, int key) { static unsigned pad[128], p; if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; for (p=4; p < 127; p++) pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } while (len-- && p++) *data++ ^= pad[(p-1) & 127] = pad[p & 127] ^ pad[(p+64) & 127]; } int parse_tiff_ifd (int base, int level) { int entries, tag, type, count, slen, save, save2, i; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; FILE *sfp; entries = get2(); if (entries > 1024) return 1; while (entries--) { save = ftell(ifp); tag = get2(); type = get2(); count= get4(); slen = count; if (slen > 128) slen = 128; tiff_dump (base, tag, type, count, level); if (type == 13) tag = 0x14a; switch (tag) { case 271: /* Make tag */ fgets (make, slen, ifp); break; case 272: /* Model tag */ fgets (model, slen, ifp); break; case 33405: /* Model2 tag */ fgets (model2, slen, ifp); break; case 330: /* SubIFD tag */ save2 = ftell(ifp); for (i=0; i < count; i++) { printf ("SubIFD #%d:\n", i+1); fseek (ifp, save2 + i*4, SEEK_SET); fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base, level+1); } break; case 273: /* StripOffset */ case 513: /* JpegIFOffset */ case 61447: fseek (ifp, get4()+base, SEEK_SET); case 46: parse_thumb (ftell(ifp), level); break; case 29184: sony_offset = get4(); break; case 29185: sony_length = get4(); break; case 29217: sony_key = get4(); break; case 29264: parse_minolta (ftell(ifp)); break; case 33424: case 65024: puts("Kodak private data:"); fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base, level+1); break; case 34310: parse_mos(0); break; case 34665: fseek (ifp, get4()+base, SEEK_SET); parse_exif (base, level+1); break; case 34853: puts("GPS data:"); fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base, level+1); break; case 50459: i = order; save2 = ftell(ifp); order = get2(); fseek (ifp, save2 + (get2(),get4()), SEEK_SET); parse_tiff_ifd (save2, level+1); order = i; break; case 50706: is_dng = 1; break; case 50740: if (is_dng) break; parse_minolta (i = get4()+base); fseek (ifp, i, SEEK_SET); parse_tiff_ifd (base, level+1); } fseek (ifp, save+12, SEEK_SET); } if (sony_length && (buf = malloc(sony_length))) { fseek (ifp, sony_offset, SEEK_SET); fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); sfp = ifp; if ((ifp = tmpfile())) { fwrite (buf, sony_length, 1, ifp); fseek (ifp, 0, SEEK_SET); puts ("Sony SR2 encrypted IFD:"); parse_tiff_ifd (-sony_offset, level); fclose (ifp); } ifp = sfp; free (buf); } return 0; } /* Parse a TIFF file looking for camera model and decompress offsets. */ void parse_tiff (int base, int level) { int doff, ifd=0, sorder=order; fseek (ifp, base, SEEK_SET); order = get2(); if (order != 0x4949 && order != 0x4d4d) return; get2(); while ((doff = get4())) { fseek (ifp, doff+base, SEEK_SET); printf ("%*sIFD #%d:\n", level*2, "", ifd++); if (parse_tiff_ifd (base, level)) break; } order = sorder; } void parse_minolta (int base) { unsigned offset, save, len, j; char tag[4]; fseek (ifp, base, SEEK_SET); if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; order = fgetc(ifp) * 0x101; offset = base + get4() + 8; while ((save=ftell(ifp)) < offset) { fread (tag, 1, 4, ifp); len = get4(); printf ("Minolta tag %3.3s offset %06x length %06x", tag+1, save, len); if (!strncmp (tag+1,"TTW",3)) { putchar ('\n'); parse_tiff (ftell(ifp),0); } else { for (j = 0; j < len/2 && j < 128; j++) printf ("%c%04x",(j & 15) || len < 9 ? ' ':'\n', get2()); putchar ('\n'); } fseek (ifp, save+len+8, SEEK_SET); } } /* Parse the CIFF structure. */ void parse_ciff (int offset, int length, int level) { int tboff, nrecs, i, j, type, len, dlen, roff, aoff=0, save; char c, name[256]; ushort key[2]; fseek (ifp, offset+length-4, SEEK_SET); tboff = get4() + offset; fseek (ifp, tboff, SEEK_SET); nrecs = get2(); if (nrecs > 100) return; printf ("%*s%d records:\n", level*2, "", nrecs); for (i = 0; i < nrecs; i++) { save = ftell(ifp); type = get2(); printf ("%*stype=0x%04x", level*2, "", type); if (type & 0x4000) { len = 8; type &= 0x3fff; } else { len = get4(); roff = get4(); aoff = offset + roff; printf (", length=%d, reloff=%d, absoff=%d", len, roff, aoff); fseek (ifp, aoff, SEEK_SET); } if ((type & 0xe700) == 0) printf (", data="); if (type == 0x0032) /* display as words */ type |= 0x1000; dlen = len < DLEN ? len:DLEN; switch (type >> 8) { case 0x28: case 0x30: putchar('\n'); parse_ciff (aoff, len, level+1); fseek (ifp, save+10, SEEK_SET); continue; case 0x00: /* byte values */ for (j = 0; j < dlen; j++) printf ("%c%02x",(j & 31) || dlen < 16 ? ' ':'\n', fgetc(ifp) & 0xff); break; case 0x08: /* null-terminated ASCII strings */ putchar('\"'); for (j = 0; j < dlen; j++) { c = fgetc(ifp); putchar( isprint(c) ? c:'.'); } putchar('\"'); break; case 0x10: /* word values */ key[0] = get2(); fseek (ifp, -2, SEEK_CUR); if (type == 0x1032 && key[0] == 1040) key[1] = 17907; else key[0] = key[1] = 0; for (j = 0; j < dlen; j+=2) printf ("%c%5u",(j & 31) || dlen < 16 ? ' ':'\n', get2() ^ key[(j >> 1) & 1]); break; case 0x18: /* dword values */ for (j = 0; j < dlen; j+=4) printf ("%c%08x",(j & 31) || dlen < 16 ? ' ':'\n', get4()); } putchar('\n'); fseek (ifp, save+10, SEEK_SET); if (type == 0x080a) { /* Get the camera name */ fseek (ifp, aoff, SEEK_SET); fread (name, 256, 1, ifp); strcpy (make, name); strcpy (model, name + strlen(make)+1); } } } int parse_jpeg (int offset) { int len, save, hlen; fseek (ifp, offset, SEEK_SET); if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) { order = 0x4d4d; len = get2() - 2; save = ftell(ifp); order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ parse_ciff (save+hlen, len-hlen, 0); parse_tiff (save+6,0); fseek (ifp, save+len, SEEK_SET); } return 1; } void parse_riff (int level) { unsigned i, size, end, save; char tag[4], type[4], buf[64]; order = 0x4949; fread (tag, 4, 1, ifp); size = get4(); if (isdigit(tag[0])) { fseek (ifp, size, SEEK_CUR); return; } printf ("%*.4s size %d", level*4+4, tag, size); if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { end = ftell(ifp) + size; fread (type, 4, 1, ifp); printf (" type %.4s:\n", type); while (ftell(ifp)+7 < end) parse_riff (level+1); } else { save = ftell(ifp); fread (buf, 1, 40, ifp); printf (": "); for (i=0; i < 40 && isprint(buf[i]); i++) putchar (buf[i]); putchar ('\n'); fseek (ifp, save+size, SEEK_SET); } } void parse_mos(int level) { char data[256]; int i, skip, save; char *cp; save = ftell(ifp); while (1) { if (get4() != 0x504b5453) break; get4(); printf ("%*sPKTS ", level, ""); fread (data, 1, 40, ifp); skip = get4(); printf ("%s %d bytes: ", data, skip); if (!strcmp(data,"pattern_ratation_angle")) { printf ("%d\n", get2()); continue; } if (!strcmp(data,"icc_camera_to_tone_matrix")) { for (i=0; i < skip/4; i++) printf ("%f ", int_to_float(get4())); putchar('\n'); continue; } fread (data, 1, sizeof data, ifp); fseek (ifp, -sizeof data, SEEK_CUR); data[sizeof data - 1] = 0; while ((cp=strchr(data,'\n'))) *cp = ' '; printf ("%s\n",data); parse_mos(level+2); fseek (ifp, skip, SEEK_CUR); } fseek (ifp, save, SEEK_SET); } void parse_rollei() { char line[128], *val; fseek (ifp, 0, SEEK_SET); do { fgets (line, 128, ifp); fputs (line, stdout); if ((val = strchr(line,'='))) *val++ = 0; else val = line + strlen(line); } while (strncmp(line,"EOHD",4)); strcpy (make, "Rollei"); strcpy (model, "d530flex"); } void get_utf8 (int offset, char *buf, int len) { ushort c; char *cp; fseek (ifp, offset, SEEK_SET); for (cp=buf; (c = get2()) && cp+3 < buf+len; ) { if (c < 0x80) *cp++ = c; else if (c < 0x800) { *cp++ = 0xc0 + (c >> 6); *cp++ = 0x80 + (c & 0x3f); } else { *cp++ = 0xe0 + (c >> 12); *cp++ = 0x80 + (c >> 6 & 0x3f); *cp++ = 0x80 + (c & 0x3f); } } *cp = 0; } void parse_foveon() { unsigned entries, off, len, tag, save, i, j, k, pent, poff[256][2]; char name[128], value[128], *camf, *pos, *cp, *dp; unsigned val, wide, high, row, col, diff, type, num, ndim, dim[3]; ushort huff[258], vpred[2][2], hpred[2]; order = 0x4949; /* Little-endian */ fseek (ifp, -4, SEEK_END); fseek (ifp, get4(), SEEK_SET); if (get4() != 0x64434553) { /* SECd */ printf ("Bad Section identifier at %6x\n", (int)ftell(ifp)-4); return; } get4(); entries = get4(); while (entries--) { off = get4(); len = get4(); tag = get4(); save = ftell(ifp); fseek (ifp, off, SEEK_SET); printf ("%c%c%c%c at offset %06x, length %06x, ", tag, tag >> 8, tag >> 16, tag >> 24, off, len); if (get4() != (0x20434553 | (tag << 24))) { printf ("Bad Section identifier at %6x\n", off); return; } val = get4(); printf ("version %d.%d, ",val >> 16, val & 0xffff); switch (tag) { case 0x32414d49: /* IMA2 */ case 0x47414d49: /* IMAG */ printf ("type %d, " , get4()); printf ("format %2d, " , get4()); printf ("columns %4d, " , get4()); printf ("rows %4d, " , get4()); printf ("rowsize %d\n" , get4()); parse_jpeg (off+28); order = 0x4949; break; case 0x464d4143: /* CAMF */ type = get4(); printf ("type %d\n", type); get4(); get4(); wide = get4(); high = get4(); if (type == 2) { camf = malloc (len -= 28); fread (camf, 1, len, ifp); for (i=0; i < len; i++) { high = (high * 1597 + 51749) % 244944; val = high * (INT64) 301593171 >> 24; camf[i] ^= ((((high << 8) - val) >> 1) + val) >> 17; } } else if (type == 4) { camf = malloc (len = wide*high*3/2); memset (huff, 0xff, sizeof huff); huff[0] = 8; for (i=0; i < 13; i++) { tag = getc(ifp); val = getc(ifp); for (j=0; j < 256 >> tag; ) huff[val+ ++j] = tag << 8 | i; } fseek (ifp, 6, SEEK_CUR); getbits(-1); vpred[0][0] = vpred[0][1] = vpred[1][0] = vpred[1][1] = 512; for (j=row=0; row < high; row++) { for (col=0; col < wide; col++) { diff = ljpeg_diff(huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if (col & 1) { camf[j++] = hpred[0] >> 4; camf[j++] = hpred[0] << 4 | hpred[1] >> 8; camf[j++] = hpred[1]; } } } } else { printf ("Unknown CAMF type %d\n", type); break; } for (pos=camf; (unsigned) (pos-camf) < len; pos += sget4(pos+8)) { if (strncmp (pos, "CMb", 3)) goto done; val = sget4(pos+4); printf (" %4.4s version %d.%d: ", pos, val >> 16, val & 0xffff); switch (pos[3]) { case 'M': cp = pos + sget4(pos+16); type = sget4(cp); ndim = sget4(cp+4); dim[0] = dim[1] = dim[2] = 1; printf ("%d-dimensonal array %s of type %d:\n Key: (", ndim, pos+sget4(pos+12), sget4(cp)); dp = pos + sget4(cp+8); for (i=ndim; i--; ) { cp += 12; dim[i] = sget4(cp); printf ("%s %d%s", pos+sget4(cp+4), dim[i], i ? ", ":")\n"); } for (i=0; i < dim[2]; i++) { for (j=0; j < dim[1]; j++) { printf (" "); for (k=0; k < dim[0]; k++) switch (type) { case 5: printf ("%7d", *(uchar *)dp++); break; case 0: case 6: printf ("%7d", (short) sget2(dp)); dp += 2; break; case 1: case 2: printf (" %d", sget4(dp)); dp += 4; break; case 3: val = sget4(dp); printf (" %9f", int_to_float(val)); dp += 4; } printf ("\n"); } printf ("\n"); } break; case 'P': val = sget4(pos+16); num = sget4(pos+val); printf ("%s, %d parameters:\n", pos+sget4(pos+12), num); cp = pos+val+8 + num*8; for (i=0; i < num; i++) { val += 8; printf (" %s = %s\n", cp+sget4(pos+val), cp+sget4(pos+val+4)); } break; case 'T': cp = pos + sget4(pos+16); printf ("%s = %.*s\n", pos+sget4(pos+12), sget4(cp), cp+4); break; default: printf ("\n"); } } done: free (camf); break; case 0x504f5250: /* PROP */ printf ("entries %d, ", pent=get4()); printf ("charset %d, ", get4()); get4(); printf ("nchars %d\n", get4()); off += pent*8 + 24; if ((unsigned) pent > 256) pent=256; for (i=0; i < pent*2; i++) poff[0][i] = off + get4()*2; for (i=0; i < pent; i++) { get_utf8 (poff[i][0], name, 128); get_utf8 (poff[i][1], value, 128); printf (" %s = %s\n", name, value); if (!strcmp (name,"CAMMANUF")) strcpy (make, value); if (!strcmp (name,"CAMMODEL")) strcpy (model, value); } } fseek (ifp, save, SEEK_SET); } } void parse_fuji (int offset) { int entries, tag, len; fseek (ifp, offset, SEEK_SET); if (!(len = get4())) return; printf ("Fuji Image %c:\n", offset < 100 ? 'S':'R'); fseek (ifp, len, SEEK_SET); entries = get4(); if (entries > 255) return; while (entries--) { tag = get2(); len = get2(); printf ("Fuji tag=0x%x, len=%d, data =",tag,len); while (len--) printf (" %02x",fgetc(ifp)); putchar ('\n'); } } void parse_phase_one (int base) { unsigned entries, tag, type, len, data, save; unsigned meta=0, wide=0, high=0, i, j; char str[256]; fseek (ifp, base, SEEK_SET); order = get4() & 0xffff; if (get4() >> 8 != 0x526177) return; fseek (ifp, base+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); type = get4(); len = get4(); data = get4(); save = ftell(ifp); printf ("Phase One tag=0x%x, type=%d, len=%2d, data = 0x%x", tag, type, len, data); if (type == 4 && len == 4 && data > 0xfffffff) printf (" = %f", int_to_float(data)); putchar ('\n'); if (tag == 0x110) meta = base+data; if (len > 4) fseek (ifp, base+data, SEEK_SET); if (type == 1 && len < 256) { fread (str, 256, 1, ifp); puts (str); } if (tag != 0x21c && type == 4 && len > 4) { for ( ; len > 0; len -= 4) printf ("%f ", int_to_float(get4())); puts (""); } fseek (ifp, save, SEEK_SET); } strcpy (make, "Phase One"); strcpy (model, "unknown"); if (!meta) return; fseek (ifp, meta, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); len = get4(); data = get4(); save = ftell(ifp); printf ("Phase One meta tag=0x%x, len=%2d, offset = 0x%x, data = ", tag, len, data); if (!((0x000801f4 >> (tag-0x400)) & 1)) putchar ('\n'); fseek (ifp, meta+data, SEEK_SET); switch (tag) { case 0x400: for (i=0; i < len; i+=2) printf ("%5u%c", get2(), (i & 6) == 6 || i == len-2 ? '\n':' '); break; case 0x401: for (i=0; i < 16; i+=2) printf ("%6u%c", get2(), (i & 14) == 14 || i == len-2 ? '\n':' '); for (; i < len; i+=4) printf ("%9.6f%c", int_to_float(get4()), (i & 28) == 12 || i == len-4 ? '\n':' '); break; case 0x402: printf ("%f\n", int_to_float (data)); break; case 0x404: case 0x405: case 0x406: case 0x407: fread (str, 256, 1, ifp); puts (str); break; case 0x408: case 0x413: printf ("%lf\n", get_double()); break; case 0x40b: case 0x410: case 0x416: for (i=0; i < len; i+=2) printf ("%6u%c", get2(), (i & 14) == 14 || i == len-2 ? '\n':' '); break; case 0x40f: case 0x418: case 0x419: case 0x41a: for (i=0; i < 4; i++) printf ("%02X%c", fgetc(ifp), i == 3 ? '\n':' '); for (; i < len; i+=4) printf ("%e%c", int_to_float(get4()), i == len-4 ? '\n':' '); break; case 0x412: for (i=0; i < 36; i+=4) { printf ("%u ", j=get4()); if (i == 4) wide = j; if (i == 12) high = j*2; } printf ("%u\n", get2()); for (i=0; i < wide*high; i++) printf ("%9.6f%c", int_to_float(get4()), i % wide == wide-1 ? '\n':' '); for (i=0; i < wide*high; i++) printf ("%5u%c", get2(), i % wide == wide-1 ? '\n':' '); break; default: for (i=0; i < len; i++) printf ("%02X%c", fgetc(ifp), (i & 15) == 15 || i == len-1 ? '\n':' '); } fseek (ifp, save, SEEK_SET); } } void parse_uuid (int level) { unsigned i, len, tag; char buf[0x8000]; for (;;) { len = get2(); tag = get2(); if (!len) break; printf ("%*stag = 0x%x, len=%d, ", level*2, "", tag, len); switch (tag >> 12) { case 1: if (len-4 < sizeof buf) { fread (buf, 1,len-4, ifp); printf ("\"%.*s\"", len-4, buf); } break; case 2: for (i=4; i < len; i+=4) printf ("%f ",int_to_float(get4())); break; default: for (i=4; i < len; i++) printf ("%02x", getc(ifp)); } putchar ('\n'); } } void parse_redcine (off_t base, int level) { unsigned i, len, tag, ulen, utag; char c, ctag[4], buf[0x8000]; do { fseeko (ifp, base, SEEK_SET); len = get4(); tag = get4(); if (feof(ifp)) break; for (i=0; i < 4; i++) { ctag[i] = tag >> ((3-i) << 3); if (!isprint(ctag[i])) ctag[i] = '.'; } printf ("%*soff=0x%llx, len=%d, tag=0x%x \"%.4s\"\n", level*2, "", (INT64) base, len, tag, ctag); switch (tag) { case 0x52454431: /* RED1 */ fseek (ifp, 59, SEEK_CUR); fread (buf, 1, 256, ifp); printf (" Original name: %s\n", buf); break; case 0x52454432: /* RED2 */ fseek (ifp, 18, SEEK_CUR); case 0x52444901: /* RDI */ fseek (ifp, 88, SEEK_CUR); parse_uuid (level+1); base = -(-(base+len) & -4096); continue; #if 0 case 0x52454441: /* REDA */ fread (buf, 1, sizeof buf, ifp); fwrite (buf+24, 1, len-32, stdout); break; #endif case 0x52454456: /* REDV */ printf (" seq = %d, time = %d\n", get4(), get4()); parse_redcine (base+20, level+1); break; case 0x75756964: /* uuid */ fseek (ifp, 16, SEEK_CUR); parse_uuid (level+1); } base += len; } while (len); } void parse_crx (int level, int end) { int i, uuid[4], size, save; char tag[4], buf[400]; while ((save = ftell(ifp)) < end) { order = 0x4d4d; size = get4(); if (size < 8 || save+size > end) { fseek (ifp, -4, SEEK_CUR); fread (buf, 1, 400, ifp); printf (" ="); for (i=0; i < 400 && i < end-save; i++) printf ("%s%02x",i & 3 ? "":" ",buf[i] & 255); fseek (ifp, end, SEEK_SET); return; } fread (tag, 4, 1, ifp); printf ("\n%*.4s size %d", level*2+4, tag, size); memset (uuid, 0, 16); if (!memcmp(tag,"uuid",4)) { for (i=0; i < 4; i++) uuid[i] = get4(); fseek (ifp, -16, SEEK_CUR); printf(" = "); for (i=0; i < 16; i++) printf ("%s%02x",(0x550 >> i) & 1 ? "-":"", fgetc(ifp)); } if (!memcmp(tag,"stsd",4)) fseek (ifp, 8, SEEK_CUR); if (!memcmp(tag,"CMT",3)) { putchar ('\n'); parse_tiff (ftell(ifp),level+1); } else parse_crx (level+1, save+size); fseek (ifp, save+size, SEEK_SET); } if (!level) { printf ("Finished parsing at offset 0x%lx, ",ftell(ifp)); printf ("mdat %sfound\n", get4() == 0x6d646174 ? "":"not "); } } void parse_qt (int level, int end) { unsigned i, lcase, size, save; char tag[4], buf[64]; order = 0x4d4d; while (ftell(ifp)+7 < end) { save = ftell(ifp); if ((size = get4()) < 8) return; fread (tag, 4, 1, ifp); printf ("%*.4s size %d", level*4+4, tag, size); for (lcase=1, i=0; i < 4; i++) if (!islower(tag[i])) lcase = 0; if (lcase && memcmp(tag,"ftyp",4) && memcmp(tag,"tkhd",4) && memcmp(tag,"mdat",4) || !memcmp(tag,"CNOP",4) || !memcmp(tag,"CNTH",4)) { putchar ('\n'); parse_qt (level+1, save+size); } else if (!memcmp(tag,"CNDA",4)) { puts (" *** parsing JPEG thumbnail ..."); parse_jpeg (ftell(ifp)); } else { fread (buf, 1, 40, ifp); printf (" : "); for (i=0; i < 40 && i < size-8; i++) putchar (isprint(buf[i]) ? buf[i] : '.'); putchar ('\n'); } fseek (ifp, save+size, SEEK_SET); } } char *memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen) { char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return NULL; } /* Identify which camera created this file, and set global variables accordingly. Return nonzero if the file cannot be decoded. */ void identify() { char head[32], *cp; unsigned hlen, fsize, toff, tlen; make[0] = model[0] = model2[0] = is_dng = 0; order = get2(); hlen = get4(); fseek (ifp, 0, SEEK_SET); fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); fsize = ftell(ifp); if ((cp = memmem (head, 32, "MMMM", 4)) || (cp = memmem (head, 32, "IIII", 4))) { parse_phase_one (cp-head); if (cp-head) parse_tiff (0,0); } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp(head+6,"HEAPCCDR",8)) { parse_ciff (hlen, fsize - hlen, 0); fseek (ifp, hlen, SEEK_SET); } else parse_tiff (0,0); } else if (!memcmp (head,"NDF0",4)) { parse_tiff (12,0); } else if (!memcmp (head,"\0MRM",4)) { parse_minolta (0); } else if (!memcmp (head,"FUJIFILM",8)) { fseek (ifp, 84, SEEK_SET); toff = get4(); tlen = get4(); parse_fuji (92); fseek (ifp, 100, SEEK_SET); parse_tiff (get4(),0); if (toff > 120) { parse_fuji (120); fseek (ifp, 128, SEEK_SET); parse_tiff (get4(),0); } parse_thumb (toff,0); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); parse_riff(0); } else if (!memcmp (head+4,"ftypcrx ",8)) { fseek (ifp, 0, SEEK_SET); parse_crx (0, fsize); } else if (!memcmp (head+4,"ftypqt ",9)) { fseek (ifp, 0, SEEK_SET); parse_qt (0, fsize); } else if (!memcmp (head+4,"RED",3)) parse_redcine(0,0); else if (!memcmp (head,"DSC-Image",9)) parse_rollei(); else if (!memcmp (head,"FOVb",4)) parse_foveon(); parse_jpeg(0); } int main(int argc, char **argv) { int arg; if (argc == 1) { fprintf (stderr, "\nRaw Photo Parser" "\nby Dave Coffin, dcoffin a cybercom o net" "\n\nUsage: %s file1.crw file2.crw ...\n", argv[0]); return 1; } for (arg=1; arg < argc; arg++) { fname = argv[arg]; ifp = fopen (fname,"rb"); if (!ifp) { perror (fname); continue; } printf ("\nParsing %s:\n", fname); identify(); fclose (ifp); } return 0; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor