#!/usr/bin/env python import struct import string #00 byte values #08 string #10 word values #18 dword #20 file/data? THMB_BIG = 0x2007 THMB_SML = 0x2008 FILE_CRW = 0x0816 FILE_THM = 0x0817 #0805 desc str #0815 fmt:desc str #080a make NUL model NUL #080b firmware str #0810 owner's name #080d location? #102a shr[7] == white balance index #102c g2? white balance red = shr[51] / shr[50], blue = shr[52] / shr[53] #0031 eos d30? red = shr[37] / shr[36], blue = shr[38] / shr[39] #10a9 d60 #1031 wid = shr[1], height = shr[2] #1835 decoder table? def readstruct(fh, fmt): return struct.unpack(fmt, fh.read(struct.calcsize(fmt))) #''.join(filter(lambda x: x not in string.printable, map(chr, range(256)))) #lambda x: string.maketrans(x, '.' * len(x)) #def makeprintable(x, a = string.maketrans def parse_ciff(fh, offset, length, endian): fh.seek(offset + length - 4) tboff = readstruct(fh, endian + "I")[0] + offset fh.seek(tboff) nrecs = readstruct(fh, endian + "H")[0] for i in range(nrecs): type = readstruct(fh, endian + "H")[0] if type & 0x4000: len = 8 type &= 0x3fff aoff = fh.tell() fh.read(8) else: len, roff = readstruct(fh, endian + "II") aoff = offset + roff; save = fh.tell() olen = len if len > 70: print 'limiting value, originally', len len = 70 if 1: if type >> 8 in [ 0x28, 0x30]: print 'recursing in parse_ciff', aoff, olen parse_ciff(fh, aoff, olen, endian) print 'back' elif 0 and type in [ THMB_BIG, THMB_SML ]: fh.seek(aoff) open('%x.jpg' % type, "a+").write(fh.read(olen)) else: fh.seek(aoff) data = fh.read(len) print "%04x: %s" % (type, ''.join(map(lambda x: '%02x' % ord(x), data))) print " %s" % repr(data) elif type == 0x080a: # handle camera name pass elif type == 0x1835: fh.seek(aoff + 2) width, height = readstruct(fh, "HH") fh.seek(save) def idcrw(fh): fh.seek(0) if fh.read(2) == "MM": endian = ">" else: endian = "<" hlen = readstruct(fh, endian + "H")[0] if hlen == 0x2a: #Tiff hoff = readstruct(fh, endian + "I")[0] raise NotImplementedError, "can't handle TIFF's" elif hlen == 0x1a: #CRW fh.seek(2) hlen = readstruct(fh, endian + "I")[0] if fh.read(8) != "HEAPCCDR": raise ValueError, "not a CRW file" fh.seek(0, 2) parse_ciff(fh, hlen, fh.tell() - hlen, endian) if __name__ == '__main__': import sys map(idcrw, map(open, sys.argv[1:]))