Commits

Pelican committed 843e96a Merge

Merge to main

  • Participants
  • Parent commits 8189b79, bde2efc

Comments (0)

Files changed (59)

 dropbox: all
 	cp $(PLATFORM_PATH)/all/autoexec.bin ~/Dropbox/Public/bleeding-edge/
 
+
+# for changelog
+HG_TEMPLATE=--template '{node|short} | {author|user}: {desc|strip|firstline} \n'
+HG_DATE=`date -d '$(1)' +'%Y-%m-%d %H:%M:%S'`
+HG_DATE_RANGE=--date "$(call HG_DATE, $(1)) to $(call HG_DATE, $(2))"
+HG_CHANGESET_BEFORE_DATE=$(shell hg log --limit 1 --date "<$(call HG_DATE, $(1) )" --template '{node|short} \n')
+
+DIFFSTAT_FILTER=python -c 'import sys; \
+	from textwrap import wrap; \
+	L = sys.stdin.readlines() or ["No changes."]; \
+	L,last = L[:-1],L[-1]; \
+	L.sort(key=lambda l: -len(l)); \
+	F = [l.split("|")[0].strip() for l in L]; \
+	brk = max(len(L)/20, 3); \
+	sys.stdout.writelines(L[:brk]); \
+	sys.stdout.write("\n ".join(wrap(", ".join(F[brk:]), width=100, break_on_hyphens=False, break_long_words=False, initial_indent=" "))); \
+	sys.stdout.write("\n\n" if brk < len(L) else ""); \
+	sys.stdout.write(last); \
+	'
+
 # today's changes are considered in last 24 hours, before compilation time
 # yesterday changes: between 24 and 48 hours
 changelog:
 	echo "===============================================================================" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
 	echo "Today's changes:" >> ChangeLog.txt
+	echo "----------------" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
-	hg log --date "`date -d 'today - 1 days' +'%Y-%m-%d %H:%M:%S'` to `date -d 'today' +'%Y-%m-%d %H:%M:%S'`" --template '{node|short} | {author|user}: {desc|strip|firstline} \n' >> ChangeLog.txt ;
+	hg log $(call HG_DATE_RANGE, today - 1 days, today) $(HG_TEMPLATE) >> ChangeLog.txt ;
+	echo "" >> ChangeLog.txt
+	COLUMNS=80 hg diff --stat -r $(call HG_CHANGESET_BEFORE_DATE, today - 1 days ) -r tip | $(DIFFSTAT_FILTER) >> ChangeLog.txt ;
+	echo "" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
 	echo "Yesterday's changes:" >> ChangeLog.txt
+	echo "--------------------" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
-	hg log --date "`date -d 'today - 2 days' +'%Y-%m-%d %H:%M:%S'` to `date -d 'today - 1 days' +'%Y-%m-%d %H:%M:%S'`" --template '{node|short} | {author|user}: {desc|strip|firstline} \n' >> ChangeLog.txt ;
+	hg log $(call HG_DATE_RANGE, today - 2 days, today - 1 days) $(HG_TEMPLATE) >> ChangeLog.txt ;
+	echo "" >> ChangeLog.txt
+	COLUMNS=80 hg diff --stat -r $(call HG_CHANGESET_BEFORE_DATE, today - 2 days) -r $(call HG_CHANGESET_BEFORE_DATE, today - 1 days) | $(DIFFSTAT_FILTER) >> ChangeLog.txt ;
+	echo "" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
 	echo "Changes for last 30 days:" >> ChangeLog.txt
+	echo "-------------------------" >> ChangeLog.txt
 	echo "" >> ChangeLog.txt
-	hg log --date "`date -d 'today - 30 days' +'%Y-%m-%d %H:%M:%S'` to `date -d 'today - 2 days' +'%Y-%m-%d %H:%M:%S'`" --template '{node|short} | {date|shortdate} | {author|user}: {desc|strip|firstline} \n' >> ChangeLog.txt ;
-
+	hg log $(call HG_DATE_RANGE, today - 30 days, today - 2 days) $(HG_TEMPLATE) >> ChangeLog.txt ;
+	echo "" >> ChangeLog.txt
+	COLUMNS=80 hg diff --stat -r $(call HG_CHANGESET_BEFORE_DATE, today - 30 days) -r $(call HG_CHANGESET_BEFORE_DATE, today - 2 days) | $(DIFFSTAT_FILTER) >> ChangeLog.txt ;
+ 
 nightly: clean all changelog
 	mkdir -p $(NIGHTLY_DIR)
 	cd $(PLATFORM_PATH)/all; $(MAKE) zip

File Makefile.inc

 	-I$(PLATFORM_INC) \
 	-I$(SRC_DIR) \
 	-I$(PICOC_PATH) \
+	-mthumb-interwork \
 
 NOT_USED_FLAGS=\
 	-march=armv5te \
 %.o: $(SRC_DIR)/%.c
 	$(call build,CC,$(CC) $(CFLAGS) -c -o $@ $<)
 %.o: $(PICOC_PATH)/%.c
-	$(call build,CC,$(CC) $(CFLAGS) -c -o $@ $<)
+	$(call build,CC,$(CC) $(CFLAGS) -c -mthumb -o $@ $<)
 %.i: %.c
 	$(call build,CPP,$(CC) $(CFLAGS) -E -c -o $@ $<)
 %: %.c

File Makefile.user.default

File contents unchanged.

File contrib/indy/dump_fir.py

+#dump decrypted thing
+
+from struct import unpack
+import os
+import sys
+import array
+import ctypes
+from optparse import OptionParser
+
+version_id = "0.5 (22dec2012)"
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+def writePatch(m, filename, patch, n):
+  name = filename+'_'+'{0:02x}'.format(n)+'.bin'
+  s = patch[n][1]
+  e = patch[n][1] + patch[n][2]
+  print 'writing %s [0x%x-0x%x]. size=0x%x/%d' % (name, s, e, patch[n][2], patch[n][2])
+  f = open(name, 'wb')
+  f.write( m[ s: e ] )
+  f.close()
+
+parser = OptionParser(usage="usage: %prog [options] filename")
+parser.add_option("-x", "--extract", type="int", dest="extract", default=-1, help="extract specified patch")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=True, help="verbose mode")
+parser.add_option("-d", "--dump", action="store_true", dest="dump", default=False, help="dump patches")
+#parser.add_option("-p", "--prefix", type="string", dest="filename", default=sys.argv[len(sys.argv)-1][:8], help="filename prefix")
+parser.add_option("-p", "--prefix", type="string", dest="filename", default="firmware", help="filename prefix")
+parser.add_option("-s", "--skip", type="int", dest="skip", default=0, help="skip n bytes")
+(options, args) = parser.parse_args()
+
+f = open(args[0], 'rb')
+f.seek(options.skip)
+m = f.read()
+size = f.tell()-options.skip
+f.close()
+
+print 'Dump_fir %s\n' % version_id
+if options.verbose:
+  print 'fileLen = 0x%x' % size
+
+#elength = getLongLE( m, 8 ) # encrypted length
+
+fchk = getLongLE( m, 0) # embedded checksum to match
+if options.verbose:
+  print '0x000: checksum = 0x%08x' % fchk
+  print '0x004: 0x%08x' % getLongLE( m, 4)
+  print '0x008: 0x%08x' % getLongLE( m, 8)
+  print '0x00c: 0x%08x' % getLongLE( m, 12)
+cchk = sum( array.array('B', m[ 4: ]) )
+if fchk != ctypes.c_uint32(~cchk).value:
+  print "checksum error"
+  sys.exit()
+
+nb_record = getLongLE( m, 0x10)
+table_offset = getLongLE( m, 0x14)
+record_size = getLongLE( m, 0x18)
+size_after = getLongLE( m, 0x1c)
+#if (size_after+4+table_offset+(nb_record*record_size)) != size:
+#  print 'error: (size_after+4+table_offset+(nb_record*record_size)) != size:'
+if options.verbose:
+  print '0x010: nb_record = 0x%x' % nb_record
+  print '0x014: table_offset = 0x%x' % table_offset
+  print '0x018: record_size = 0x%x' % record_size
+  print '0x01c: size_after = 0x%x' % size_after
+  print '0x%03x: ---patches table---' % table_offset
+  print '      + tag  + foffset  +   size   + moffset  +    ?'
+  print   ' --------------------------------------------------------'
+patch = dict()
+n = 0
+size = 0
+for i in range(nb_record):
+   k = getLongLE( m, table_offset + record_size*i)
+   patch[ k ] = ( getLongLE( m, table_offset + record_size*i + 4 ),\
+   getLongLE( m, table_offset + record_size*i + 8 ),\
+   getLongLE( m, table_offset + record_size*i + 12 ),\
+   getLongLE( m, table_offset + record_size*i + 16 ),\
+   getLongLE( m, table_offset + record_size*i + 20 )  )
+   if options.verbose:
+     print ' 0x%02x: 0x%04x 0x%08x 0x%08x 0x%08x 0x%08x' % ( k, patch[k][0], patch[k][1], patch[k][2], patch[k][3], patch[k][4] ) 
+   n = n + patch[k][4]
+   size = size + patch[k][2]
+if options.verbose:
+  print '0x%03x: ---patch#1---' % (table_offset + nb_record*record_size)
+  print '                         0x%08x            0x%08x/%d' % (size, n, n)
+  print '%d' % (size/n)
+if options.extract != -1:
+  if options.extract == 0:
+    for i in range(nb_record):
+      writePatch(m, options.filename, patch, i+1)
+  else:
+      writePatch(m, options.filename, patch, options.extract)
+      

File contrib/indy/dump_srec.py

+# parses Canon SRec records (stored with tag #0x200) of Canon DSLR updates
+#  version 0.6 (17Sep2011)
+#  by Arm.Indy, based on initial work by JollyRoger who identified the format
+#  See http://en.wikipedia.org/wiki/SREC_%28file_format%29
+"""
+record format is: type(1byte), len(1byte), address(depending on type), data (0 to 16 bytes), checksum(1 byte)
+length is including fields [len, address if present, data]
+checksum is computed on same fields as length
+record types are:
+ 00, len, 0000, filename, checksum
+ 01, len, address(2bytes), data, checksum
+ 03, len, address(4bytes), data, checksum
+ 07, len, data, checksum
+ 09, len, data, checksum
+"""
+
+from struct import unpack
+import os
+import sys
+import array
+import ctypes
+import string
+from optparse import OptionParser
+from binascii import hexlify
+
+def getByteLE(d, a):
+   return unpack('<B',(d)[a:a+1])[0]
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+def getShortLE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+def getShortBE(d, a):
+   return unpack('>H',(d)[a:a+2])[0]
+def getLongBE(d, a):
+   return unpack('>L',(d)[a:a+4])[0]
+
+parser = OptionParser(usage="usage: %prog filename")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="verbose mode")
+parser.add_option("-x", "--extract", action="store_true", dest="extract", default=False, help="extract files")
+parser.add_option("-c", "--convert", action="store_true", dest="convert", default=False, help="convert files to S19")
+(options, args) = parser.parse_args()
+
+f = open(args[0], 'rb')
+m = f.read()
+size = f.tell()
+f.close()
+
+# Find blocks
+
+currentAddress = 0
+
+print 'Dump Canon SRec, v0.5'
+print
+
+while currentAddress < size:
+
+   rtype = getByteLE(m, currentAddress) #S0
+   if rtype <> 0:
+     print 'error rtype<>0'   
+   offset = currentAddress+1
+   rlen = getByteLE(m, currentAddress+1)
+   #Extract filename
+   fileNameLen =  rlen - 3
+   if options.verbose:
+     print "0x%06x: %02x %02x %04x" % ( currentAddress, rtype, rlen, getShortBE(m, currentAddress+2) ),
+
+   currentAddress += 4
+#   fileName = m[ currentAddress: currentAddress+fileNameLen ]
+   i = currentAddress
+   while m[ i: i+1 ] in string.printable and i<(currentAddress+fileNameLen):
+     i+=1 
+   fileName = m[ currentAddress: i ]
+   print '%s' % fileName,
+
+   fileLen = 0
+   
+   csum = sum( array.array('B', m[ currentAddress-3:  currentAddress+fileNameLen ]) )
+   if options.verbose:
+     print '%02x' % ( ctypes.c_uint32(~csum).value & 0xff ),
+   currentAddress += fileNameLen
+   rsum = getByteLE(m, currentAddress)
+   if options.verbose:
+     print '%02x' % ( rsum )
+   currentAddress += 1
+   if options.convert: #prepare S0 record in S19 record
+     dataS0 = hexlify(m[offset:offset+rlen+1])
+
+   endBlockFound = False
+   fileOpen = False
+   fileConvertOpen = False
+   startAddr = -1
+   while not endBlockFound:
+     offset = currentAddress
+     rtype = getByteLE(m, currentAddress)
+     rlen = getByteLE(m, currentAddress+1)
+     currentAddress += 2
+     if rtype == 3: #like S3
+       addrLen = 4
+       addr = getLongBE(m, currentAddress)
+       dataLen = rlen-addrLen-1
+     elif rtype == 1: #like S1
+       addrLen = 2
+       addr = getShortBE(m, currentAddress)
+       dataLen = rlen-addrLen-1
+     elif rtype == 7 or rtype == 9: #like S7 and S9
+       addrLen = 0
+       dataLen = rlen-1
+       endBlockFound = True
+       endAddr = addr
+     else:
+       print 'unsupported record type = %x' % rtype
+     
+     if startAddr <0:
+       startAddr = addr 
+     if options.extract and not fileOpen:
+       fileName = fileName+'_'+'{0:08x}'.format(addr)+'.bin'
+       f = open(fileName, 'wb')
+       fileOpen = True
+     if options.convert: #write S0 record in S19 record
+       if not fileConvertOpen:
+         fc = open(fileName+'_'+'{0:08x}'.format(addr)+'.s19', 'w')
+         fileConvertOpen = True
+         fc.write('S0'+dataS0+'\n')
+       fc.write('S'+'{0:1}'.format(rtype)+hexlify(m[offset+1:offset+rlen+2])+'\n')
+
+     currentAddress += addrLen
+     if addrLen == 4:
+       if options.verbose:
+         print "0x%06x: %02x %02x %08x" % ( offset, rtype, rlen, addr ),
+     elif addrLen == 2:
+       if options.verbose:
+         print "0x%06x: %02x %02x %04x" % ( offset, rtype, rlen, addr ),
+     else:
+       if options.verbose:
+         print "0x%06x: %02x %02x %s" % ( offset, rtype, rlen, addrLen*"  " ),
+     data = m[currentAddress: currentAddress+dataLen]
+     dataAscii = ''
+     for c in data:
+       if c in string.printable:
+         dataAscii.join(c)
+       else:
+         dataAscii.join('.')
+     if options.extract:
+       f.write( data )
+     fileLen += dataLen
+     if options.verbose:
+       print "= %-32s %-32s" % ( hexlify( data ), dataAscii ),
+     csum = sum( array.array('B', m[ offset+1:  currentAddress+dataLen ]) )
+     csum = ctypes.c_uint32(~csum).value & 0xff
+     if options.verbose:
+       print '%02x' % csum,
+     currentAddress += dataLen
+     rsum = getByteLE(m, currentAddress)
+     if options.verbose:
+       if rsum == csum:
+         print 'OK'
+       else:
+         print 'KO'
+     currentAddress += 1
+  
+   if options.convert: #write S0 record in S19 record
+     fc.close()
+   if options.extract:
+     f.close()
+     print "%d bytes saved, " % fileLen,
+   else:
+     print "%d bytes, " % fileLen,
+   print "0x%x-0x%x" % (startAddr, endAddr)  

File contrib/indy/find_audio_thr.py

+
+from binascii import hexlify, unhexlify
+import sys
+
+unhexlify('FF7F000013720000AB6500009D5A0000C2500000FA470000264000002C390000')
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+fileLen = f.tell()
+f.close()
+
+#550D 1.0.8  (DRYOS 2.3, release #0043)
+#60D 1.1.0
+#600D 1.1.0
+#5Dm2 2.0.9
+o = m.find( unhexlify('FF7F000013720000AB6500009D5A0000C2500000FA470000264000002C390000') )
+print '0x%x' % o
+
+#50D 1.0.8  (DRYOS 2.3, release #0023)
+o = m.find( unhexlify('0080000015720000AD6500009E5A0000C3500000FB470000274000002D390000') )
+print '0x%x' % o
+
+#500D (DRYOS 2.3, release #0039) ?

File contrib/indy/find_fnt.py

+
+"""
+* Pel,  15Mar2011
+http://chdk.setepontos.com/index.php?topic=6204.msg63022
+
+ROM:FF617540: 48 43 61 6e 6f 6e 47 6f 74 68 69 63 00 2f 2f 2f  HCanonGothic.///
+
+The character codes (UTF-8) listed in 32 bit format from 0xFF617550
+ROM:FF617550: 20 00 00 00 21 00 00 00 22 00 00 00 23 00 00 00   ...!..."...#...
+ROM:FF617560: 24 00 00 00 25 00 00 00 26 00 00 00 27 00 00 00  $...%...&...'...
+...
+The bitmap positions (32 bit) start after the character codes at 0xFF619CFC .
+ROM:FF619CF0: ef bc 9a 00 ef bc 9f 00 ef bd 9e 00 00 00 00 00  ................
+ROM:FF619D00: 0e 00 00 00 38 00 00 00 52 00 00 00 bc 00 00 00  ....8...R.......
+...
+The character data start after the positions at 0xFF61C4A8 .
+ROM:FF61C4A0: c6 bb 06 00 98 bc 06 00 01 00 01 00 0c 00 00 00  ................
+...
+
+The structure of the character data:  lW, hW, lH, hH, lCW, hCW, lXO, hXO, lYO, hYO, DT[], PD[]
+lW,hW: width of the bitmap (low, high)
+lH,hH: height of the bitmap
+lCW,hCW: the actual character width
+lXO,hXO: X offset of the character bitmap data
+lYO,hYO: Y offset of the character bitmap data
+DT[]: data bytes of the character bitmap, size: H*round up(W / 8 )
+PD[]: padding bytes: 0-4(?) zero byte;
+
+Camera	'HCanonGothic'	Char codes	Offsets	    Bitmaps	    chars
+5D2	    0xFF05E9B0      0xFF05E9C0	0xFF061108	0xFF063850	2514
+7D	    0xFF617540	    0xFF617550	0xFF619CFC	0xFF61C4A8	2539
+60D	    0xFF7B1FA8	    0xFF7B1FB8	0xFF7B4644	0xFF7B6CD0	2467
+50D	    0xFF05E1C8	    0xFF05E1D8	0xFF0608EC	0xFF063000	2501
+600D	0xFF89476C	    0xFF89477C	0xFF8971B0	0xFF899BE4	2701
+550D	0xFF661A94	    0xFF661AA4	0xFF663F84	0xFF666464	2360
+
+* Trammel Hudson, 19Mar2011
+http://groups.google.com/group/ml-devel/browse_frm/thread/aec4c80eef1cdd6a/fb2748e11517344e
+
+struct font
+{
+        uint32_t magic; // 0x464e5400 == "FNT\0"
+        uint16_t off_0x4; // 0xffe2 in most of them?
+        uint16_t font_width; // off_0x6;
+        uint32_t charmap_offset; // off_0x8, typicaly 0x24
+        uint32_t charmap_size; // off_0xc
+        uint32_t bitmap_size; // off_0x10
+        const char name[16];
+
+};
+
+On the 5D there are the following fonts added to the stubs.S file:
+
+0xf005e99c: HCanonGothic 40 px, utf8 (0xFFD8)
+0xf00cdf54: HCanonGothic 30 px, ascii only (0xFFE2)
+0xf00d1110: HCanonGothic 36 px, ascii only (0xFFE2)
+0xf00d585c: CanonMonoSpace 40 px, ascii only (0xFFD8)
+
+
+Alex, 16Mar2011
+https://bitbucket.org/hudson/magic-lantern/changeset/cfba492ea84d
+
+
+"""
+
+import sys
+from struct import unpack
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+def getShortLE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+
+def parseFont(m, off, base):
+  print '0x%08x: %s' % (base+off, m[off:off+4] )
+  print '0x%08x: (+0x04) 0x%x' % ( base+off+4, getShortLE(m, off+4) )  
+  print '0x%08x: (+0x06) font_width = %d' % ( base+off+6, getShortLE(m, off+6) ) 
+  charmap_offset = getLongLE(m, off+8) 
+  print '0x%08x: (+0x08) charmap_offset = 0x%x' % ( base+off+8, charmap_offset )
+  charmap_size = getLongLE(m, off+12)
+  print '0x%08x: (+0x0c) charmap_size = 0x%x' % ( base+off+12, charmap_size )
+  print '0x%08x: (+0x10) bitmap_size = 0x%x' % ( base+off+16, getLongLE(m, off+16) )
+  print '0x%08x: (+0x14) font name = \'%s\'' % ( base+off+20, m[off+20: off+36] )
+  nb_char = charmap_size/4
+  print '0x%08x: (+0x%02x) char_codes[]. %d chars' % ( base+off+charmap_offset, charmap_offset, nb_char )
+  last_offset = getLongLE(m, off + charmap_offset + charmap_size + (nb_char-1)*4 )
+  print '0x%08x: (+0x%02x) offsets[]. Last offset value = 0x%x' % ( base+off+charmap_offset+charmap_size, charmap_offset+charmap_size, last_offset )
+  bitmap_offset = charmap_offset+charmap_size+nb_char*4
+  print '0x%08x: (+0x%02x) bitmaps[]' % ( base+off+bitmap_offset, bitmap_offset  )
+  print '  0x%06x: (+0x%02x) last bitmap' % ( base+off+bitmap_offset+last_offset, bitmap_offset+last_offset  )
+  parseBitmap( m, off+bitmap_offset+last_offset, base )
+  print  
+
+def parseBitmap(m, off, base):
+  width = getShortLE(m, off)
+  print '  +0x%02x: bitmap width = %d' % (0, width )
+  height = getShortLE(m, off)
+  print '  +0x%02x: bitmap height = %d' % (2, height )
+  print '  +0x%02x: char width = %d' % (4, getShortLE(m, off+4) )
+  print '  +0x%02x: X offset = %d' % (6, getShortLE(m, off+6) )
+  print '  +0x%02x: Y offset = %d' % (8, getShortLE(m, off+8) )
+  nb_byte = width/8
+  if width%8 > 0:
+    nb_byte = nb_byte + 1
+  print '    bitmap size = 0x%x' % ( nb_byte*height )
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+f.close()
+
+if (len(sys.argv)>2):
+  base = int(sys.argv[2], 16)
+else:
+  base = 0xff010000
+
+print 'Find bitmap fonts in Canon DSLR firmwares'
+print 'Arm.Indy. based on work by Pel, Trammel Hudson and A1ex\n'
+
+off = 0
+while off < len(m) and off <> -1: 
+  off = m.find('FNT\0', off)
+  if off <> -1:
+    val = getShortLE(m, off+4)
+    if val==0xffd8 or val==0xffe2:
+      parseFont(m, off, base)
+    off = off + 4 

File contrib/indy/fir_tool2.py

+# fir_tool.py 
+# Copyright (C) 2010 Arm.Indy arm.indiana at google mail
+"""
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+ 
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the
+Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor,
+Boston, MA  02110-1301, USA.
+"""
+import os
+import sys
+import array
+from struct import unpack
+import ctypes
+from binascii import hexlify, unhexlify
+from optparse import OptionParser
+
+version_id = "0.5 (20Mar2010)"
+
+# updater decoding tables. since 1d Mark III (2/2007) 
+# See 20 dec 2007 (soldeersmurfje), 40D firmware decryption, http://tech.groups.yahoo.com/group/canondigicamhacking/message/7883
+
+t512 = [0x07, 0x9E, 0xD5, 0x5E, 0x19, 0xB5, 0xE6, 0x2B, 0x17, 0xA5, 0xC1, 0xA2, 0xBD, 0x59, 0x38, 0x68, 
+  0xEC, 0xFE, 0x2D, 0x8C, 0x14, 0x99, 0xE6, 0xB9, 0x54, 0xAD, 0x85, 0x84, 0x40, 0x48, 0xCE, 0x78,   
+  0xA4, 0xA0, 0xA7, 0x4B, 0xEC, 0x59, 0xCD, 0x93, 0xD8, 0x8C, 0xA7, 0x33, 0xB0, 0xA1, 0x78, 0x66, 
+  0x0A, 0x8C, 0xB6, 0x26, 0x80, 0xDB, 0x49, 0xC1, 0x54, 0xD9, 0x88, 0x0C, 0xA2, 0x8A, 0xF1, 0x68, 
+  0x2A, 0xBC, 0x12, 0x93, 0x23, 0x74, 0x11, 0x4C, 0x66, 0x67, 0x93, 0x81, 0x12, 0x6B, 0x04, 0x52,
+  0x79, 0xEC, 0x90, 0xD4, 0xF7, 0x1E, 0xB9, 0x6B, 0xEB, 0x6C, 0xF9, 0x86, 0x58, 0x97, 0xDA, 0xF0, 
+  0x7D, 0x3D, 0xC4, 0xEA, 0x8F, 0x48, 0x75, 0x21, 0x62, 0xC7, 0x5F, 0xFB, 0x93, 0xF9, 0xC3, 0x91, 
+  0x83, 0xF6, 0x64, 0x46, 0xA9, 0x14, 0x64, 0xCB, 0xF2, 0x4C, 0xAB, 0x8F, 0xE9, 0xAE, 0xC9, 0xE8, 
+  0xC3, 0x5D, 0xC0, 0x07, 0xD4, 0xD2, 0xD5, 0xEC, 0x7E, 0x89, 0x3E, 0x65, 0x66, 0xDA, 0x2A, 0xB1, 
+  0xB7, 0xD0, 0x47, 0x0A, 0x3A, 0x93, 0x52, 0x49, 0x5F, 0xAB, 0xD7, 0x21, 0x79, 0xF0, 0xF7, 0xAF,
+  0x90, 0x60, 0x52, 0x88, 0x80, 0x7F, 0x31, 0xBA, 0xF3, 0x2D, 0x04, 0xA2, 0xE8, 0x66, 0xB5, 0x68, 
+  0x6D, 0x15, 0x58, 0x94, 0x1C, 0xC4, 0x16, 0x68, 0xF3, 0xE2, 0x20, 0x68, 0x89, 0x3E, 0x08, 0xD8, 
+  0x43, 0xA2, 0xD0, 0x27, 0x55, 0x58, 0x51, 0xF6, 0x8B, 0x49, 0x14, 0xF6, 0xE9, 0xBD, 0x37, 0xFB, 
+  0x80, 0xBA, 0x99, 0xAD, 0x4C, 0x55, 0xC1, 0xDD, 0x89, 0xDE, 0xF8, 0x2D, 0x72, 0x2C, 0xB9, 0x37, 
+  0x84, 0x45, 0x34, 0x9D, 0xBE, 0x83, 0x42, 0x9A, 0x2D, 0xD7, 0x78, 0xE5, 0x0F, 0xAC, 0xA7, 0xCC,
+  0xC3, 0x35, 0xDC, 0x56, 0x7F, 0xBD, 0xC4, 0xBF, 0xA1, 0x41, 0x44, 0x5F, 0xAD, 0x45, 0x68, 0x65, 
+  0x7F, 0x10, 0x73, 0x4B, 0x89, 0x72, 0x2F, 0xDA, 0xD0, 0xC3, 0x3F, 0x26, 0xD9, 0x5E, 0x94, 0x61, 
+  0xF8, 0x21, 0x19, 0xD5, 0xF9, 0x1B, 0x18, 0xF5, 0xDD, 0x26, 0x79, 0xF4, 0xF2, 0x44, 0x77, 0x44, 
+  0xCD, 0x83, 0x44, 0x12, 0xCE, 0x37, 0xB9, 0x25, 0xDE, 0x0F, 0x12, 0x2A, 0x5D, 0xD6, 0x7D, 0x1F, 
+  0x39, 0x10, 0x4F, 0x7F, 0xB9, 0x75, 0x1C, 0xAB, 0x8B, 0x43, 0xEB, 0x3D, 0xC1, 0x8C, 0xCB, 0x2B,
+  0x1E, 0x45, 0x7D, 0x31, 0x1A, 0xC9, 0x8B, 0xDB, 0x65, 0xD0, 0x75, 0x50, 0xEB, 0xB3, 0x65, 0xFB, 
+  0x05, 0xCE, 0xC0, 0xCF, 0x58, 0x24, 0xFB, 0x1C, 0x94, 0x4B, 0x6A, 0x15, 0xEF, 0x32, 0xB3, 0x9B, 
+  0x63, 0x91, 0xC2, 0x61, 0xE6, 0x66, 0x0A, 0xCA, 0xA8, 0xE5, 0x5B, 0x98, 0x95, 0x52, 0xAA, 0x9F, 
+  0xC5, 0xB0, 0x9D, 0x3A, 0x98, 0x43, 0x2D, 0x7D, 0x14, 0x74, 0x34, 0x6B, 0xB1, 0x11, 0x19, 0x64, 
+  0x07, 0x7D, 0x11, 0x0B, 0x13, 0x77, 0xE4, 0x46, 0x86, 0xEF, 0x2B, 0x7F, 0x5E, 0x05, 0xF1, 0xB4,
+  0x12, 0xC3, 0xAB, 0x34, 0xCA, 0x64, 0x62, 0x76, 0xA1, 0xDF, 0x37, 0x8F, 0xBF, 0xFA, 0xB3, 0x5C, 
+  0xE4, 0x59, 0x84, 0x22, 0xD1, 0x26, 0x8B, 0x5F, 0x8D, 0x44, 0x92, 0xD5, 0xDD, 0x61, 0x0F, 0xF2, 
+  0xA1, 0xC9, 0x02, 0x9C, 0x6F, 0xAC, 0x4A, 0x36, 0x99, 0x19, 0xDF, 0xF3, 0x20, 0xBF, 0xD9, 0x02, 
+  0xAE, 0x08, 0xF7, 0xC0, 0x6D, 0xA8, 0x24, 0x93, 0x94, 0xD4, 0x40, 0xF9, 0x67, 0xE2, 0x5C, 0x3B, 
+  0x37, 0xDF, 0xC8, 0xDB, 0x70, 0x18, 0xC5, 0xA2, 0x55, 0x5A, 0x04, 0xB6, 0x40, 0x63, 0xDE, 0xF6,
+  0x4C, 0x78, 0x6F, 0xC7, 0xC2, 0x59, 0xB6, 0x8B, 0xF4, 0x35, 0x31, 0x19, 0x4F, 0xE2, 0x56, 0x39, 
+  0x50, 0x5C, 0x65, 0x0C, 0x29, 0xF2, 0x22, 0xE1, 0x35, 0x51, 0xE1, 0x91, 0x89, 0x52, 0xF3, 0x64 ]
+t513 = [ 0xB8, 0xE4, 0x0F, 0xD5, 0xAC, 0x6B, 0x38, 0x5F, 0x4F, 0x75, 0x21, 0x0F, 0x38, 0x3B, 0x43, 0x0D, 0x9F, 0xD8, 0x46, 0xCA,
+  0xB0, 0x7C, 0x26, 0x71, 0x6D, 0xCA, 0xB4, 0x48, 0xBE, 0x3C, 0x96, 0xAE, 0xCE, 0x63, 0x88, 0xC2, 0x9A, 0x63, 0x49, 0x5F,
+  0xEF, 0xB9, 0x1F, 0xB8, 0x46, 0x66, 0x98, 0xF3, 0x95, 0xB9, 0xBF, 0xBA, 0x15, 0x47, 0x56, 0x3A, 0x70, 0x88, 0x0A, 0x8D,
+  0x20, 0x3C, 0x2E, 0x1A, 0x76, 0xDE, 0xE8, 0xB6, 0x9A, 0x65, 0x6B, 0xD8, 0x93, 0xF1, 0x55, 0xC5, 0x65, 0xA7, 0x97, 0xF3,
+  0xC7, 0x43, 0x2E, 0xED, 0xA5, 0x19, 0x80, 0xB4, 0xFE, 0x39, 0x02, 0xD2, 0xDE, 0xF7, 0x4D, 0x31, 0x61, 0x10, 0xC0, 0x45,
+  0x26, 0x9D, 0x37, 0x94, 0x2C, 0x19, 0xA7, 0xC7, 0x1A, 0xAC, 0xD8, 0xEC, 0xFA, 0x9D, 0x2E, 0x18, 0xFB, 0x8E, 0x26, 0x25,
+  0xAD, 0x43, 0xC0, 0x59, 0x3B, 0x6E, 0x55, 0xFA, 0x27, 0x18, 0x21, 0xED, 0x36, 0x54, 0x04, 0xB9, 0x9B, 0x54, 0x5E, 0x12,
+  0x31, 0x9E, 0x86, 0xBC, 0xD6, 0x7A, 0x54, 0xF2, 0x02, 0x8B, 0x39, 0xC1, 0x4A, 0xAD, 0x3D, 0x3A, 0x12, 0x5A, 0x90, 0x3D,
+  0xD5, 0x6F, 0x4E, 0x30, 0xE5, 0xFC, 0xAF, 0x75, 0x10, 0xB2, 0x0E, 0xE2, 0x8A, 0x9F, 0x46, 0x2B, 0x34, 0xEA, 0x87, 0x73,
+  0xB7, 0x39, 0x51, 0x9B, 0xAB, 0x62, 0x27, 0xA8, 0xF1, 0xD7, 0xE7, 0xF2, 0xE3, 0xAE, 0x9F, 0x21, 0x8F, 0x8F, 0x70, 0x0D,
+  0x4B, 0x0D, 0x7B, 0x25, 0xFC, 0xC9, 0x8C, 0xF6, 0xD5, 0x21, 0xC1, 0xC8, 0xF9, 0x75, 0xAD, 0xE7, 0xA7, 0xB3, 0xF5, 0x31,
+  0xB1, 0xF6, 0x66, 0x7B, 0xCA, 0x34, 0xDA, 0xCD, 0x37, 0xAB, 0x80, 0x44, 0x2F, 0x1C, 0x5B, 0xD3, 0x05, 0x94, 0x65, 0xC7,
+  0xDC, 0xC3, 0x82, 0xAF, 0x8F, 0xA6, 0x56, 0x62, 0x28, 0x54, 0x7E, 0xF8, 0xEE, 0x49, 0x78, 0xD9, 0x4B, 0xA8, 0x81, 0xDD,
+  0x3B, 0x71, 0xD2, 0x36, 0xB9, 0x18, 0xC9, 0x2D, 0xD7, 0x78, 0xFD, 0x66, 0xE7, 0x85, 0xF2, 0x0F, 0xFC, 0xEB, 0x8B, 0x93,
+  0x76, 0x48, 0x53, 0xF8, 0x05, 0x94, 0x93, 0xAC, 0x68, 0xE2, 0x3A, 0xB2, 0xE4, 0x65, 0x8B, 0x47, 0x75, 0x49, 0xF4, 0x5F,
+  0x59, 0x64, 0x5A, 0x16, 0x3B, 0xB2, 0xB7, 0x37, 0x50, 0xA3, 0xBA, 0x4B, 0xB4, 0xE6, 0xAF, 0x9A, 0xC7, 0x6E, 0x15, 0x51,
+  0x88, 0xB5, 0xE0, 0xFA, 0x09, 0xB4, 0x90, 0x47, 0xDD, 0x3D, 0x86, 0x90, 0xA9, 0x12, 0x30, 0x2F, 0x79, 0x83, 0xDF, 0xF1,
+  0xA8, 0x2D, 0xC9, 0xBC, 0xFB, 0xBD, 0x61, 0x93, 0x3F, 0x18, 0xB9, 0x38, 0x5C, 0xCA, 0x20, 0x58, 0x3B, 0x1C, 0xF3, 0xD9,
+  0x56, 0xBE, 0x5F, 0x1A, 0x3E, 0x0F, 0x18, 0xD5, 0xF1, 0xA2, 0xFD, 0x8B, 0xB0, 0x27, 0x67, 0x0F, 0xB8, 0x4D, 0x51, 0xEB,
+  0x8B, 0x2C, 0x50, 0x14, 0xDC, 0xD2, 0xAD, 0x7E, 0x06, 0xFE, 0x6A, 0x4D, 0x26, 0x38, 0x37, 0x9E, 0x77, 0x16, 0xBF, 0xB4,
+  0xA0, 0xF9, 0x0A, 0x64, 0x0E, 0x7F, 0xD0, 0xF4, 0xE5, 0x72, 0x82, 0x72, 0xC8, 0x7A, 0xB7, 0xEC, 0x8D, 0x53, 0x14, 0x2D,
+  0xA5, 0x98, 0xAD, 0xBE, 0x17, 0x83, 0x42, 0xD4, 0xC4, 0x04, 0xE7, 0xC2, 0x4D, 0x20, 0x05, 0xDE, 0xAA, 0xE8, 0x09, 0xE7,
+  0x45, 0x15, 0x74, 0xEF, 0x7F, 0x6E, 0x38, 0x76, 0xAA, 0x5B, 0x44, 0xCC, 0xFD, 0x82, 0x12, 0xF6, 0xDA, 0x33, 0x84, 0x0A,
+  0x6A, 0x5B, 0x34, 0xE7, 0x9E, 0x22, 0x10, 0xF5, 0x8C, 0xA0, 0xCA, 0x92, 0x58, 0xA1, 0xD0, 0x46, 0x47, 0xDA, 0xF6, 0x43,
+  0x3C, 0xF1, 0x17, 0x8F, 0x50, 0xE4, 0xFD, 0x33, 0xBD, 0x46, 0x83, 0x41, 0x0E, 0xD5, 0x27, 0x0D, 0xB2, 0x87, 0x86, 0x16,
+  0x82, 0x1D, 0xDD, 0xE7, 0xE1, 0xEF, 0x29, 0x5D, 0x48, 0xF4, 0xFC, 0xF2, 0x1D ]            
+
+VXWORKS = 0
+DRYOS = 1
+osName = [ 'VxWorks', 'DryOS' ]
+models = [ [ 0x80000169, VXWORKS, '1D Mark III'],           [ 0x80000176, VXWORKS, '450D / Rebel XSi'],
+           [ 0x80000190, VXWORKS, '40D'],                   [ 0x80000213, VXWORKS, '5D'],
+           [ 0x80000215, VXWORKS, '1Ds Mark III'],          [ 0x80000218, DRYOS,   '5D Mark II'],
+           [ 0x80000234, VXWORKS, '30D'],                   [ 0x80000236, VXWORKS, '400D / Rebel XTi'],
+           [ 0x80000250, DRYOS, '7D'],                      [ 0x80000252, DRYOS, '500D / T1i'],
+           [ 0x80000254, VXWORKS, '1000D / Rebel XS'],      [ 0x80000261, DRYOS, '50D'],
+           [ 0x80000270, DRYOS, '550D / T2i'],              [ 0x80000281, DRYOS, '1D Mark IV'],
+           [ 0x80000241, DRYOS, 'WFT-E2'],                  [ 0x80000246, DRYOS, 'WFT-E3'] ]
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+def getModel(id):
+  for i in models:
+    if i[0]==id:
+      return i[1], i[2]
+  return None, '???'
+
+#from dissect_fw3_2.rar : http://chdk.setepontos.com/index.php?action=dlattach;topic=111.0;attach=2700    
+def xor_decode( seed, start, len ):
+  o512 = ctypes.c_uint32(seed << 23).value >> 23
+  v = (seed * 0xFF803FE1) >> 32
+  o513 = seed - ((v>>9) + (v & 0xFFFFFE00))
+  out = array.array('B', m[start:start+len] )
+  for i in range(len):
+    out[i] =  out[i] ^ t512[o512] ^ t513[o513] ^ 0x37 
+    o512 = (o512+1) % 512
+    o513 = (o513+1) % 513
+  return out
+
+def check_xor_decoding( os, out):
+  if (os==VXWORKS and out[8:16].tostring() == 'Copyrigh') or (os==DRYOS and out[4:12].tostring() == 'gaonisoy'):
+    return True
+  else:
+    return False
+
+def decipher_updater( xorSeed, offset, len, filename):
+  out = xor_decode( xorSeed, offset, len)
+  print ' xor_decoding [0x%x-0x%x]...' % ( offset, offset+len),
+  if check_xor_decoding( os, out):
+    print 'OK (%s)' % filename
+    f = open(filename, 'wb')
+    out.tofile(f)
+    f.close()
+  else:
+    print 'KO'
+
+parser = OptionParser(usage="usage: %prog [options] filename")
+parser.add_option("-z", "--zeros", action="store_true", dest="zeros", help="print fields usually filled with zeros", default=False)
+parser.add_option("-c", "--checksum", action="store_true", dest="checksum", default=False, help="verify checksum(s)")
+parser.add_option("-x", "--extract", action="store_true", dest="extract", default=False, help="extract updater(s) code")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="verbose mode")
+(options, args) = parser.parse_args()
+  
+f = open(args[0], 'rb')
+m = f.read()
+fileLen = f.tell()
+f.close()
+
+print 'Fir_tool %s\n' % version_id
+print 'fileLen = 0x%x' % fileLen
+print '---.fir header---'
+model = getLongLE( m, 0 )
+print '0x000: modelId = 0x%08x,' % model,
+os, modelName = getModel( model )
+if (os!=None):
+  print '(%s, %s)' % (modelName, osName[os] )
+if options.zeros:
+  print '0x004: %s' % hexlify( m[ 4:0x10 ] ) 
+print '0x010: version = %s' % ( m[0x10:0x10+5] )
+if model==0x80000213 or model==0x80000234 or model==0x80000236: # 5D, 400D and 30D
+  print 'not supported by python version of fir_tool'
+  sys.exit()
+
+if options.zeros:
+  print '0x015: %s' % hexlify( m[ 0x15:0x20 ] ) 
+fsum = getLongLE( m, 0x20 )
+print '0x020: checksum = 0x%08x' %  fsum 
+if options.checksum:
+  csum = sum( array.array('B', m[ 0:0x20 ]) ) + sum( array.array('B', m[ 0x24:fileLen ]) )
+  if fsum != ctypes.c_uint32(~csum).value:
+   print " checksum error (decryption2) csum=%x" % (csum)
+  else:
+    print " checksum computing [0x%x-0x%x] is OK!" % (0 , fileLen)
+updater1header = getLongLE( m, 0x24 )
+updater1 = getLongLE( m, 0x28 )
+print '0x024: updater1 header = 0x%x' % ( updater1header )
+print '0x028: updater1 offset = 0x%x' % updater1
+updater2header = getLongLE( m, 0x2c )
+print '0x02c: updater2 offset = 0x%x' % updater2header
+firmware = getLongLE( m, 0x30 )
+print '0x030: firmware offset = 0x%x' % firmware
+print '0x034: 0x%x' % getLongLE( m, 0x34 )
+efileLen = getLongLE( m, 0x38 )
+print '0x038: embedded file size = 0x%x' % efileLen
+if efileLen != fileLen:
+  print 'error file size != embedded file size'
+print '0x03c: 0x%x' % getLongLE( m, 0x3c )
+print '0x040: sha1 seed = 0x%x' % getLongLE( m, 0x40 )
+print '0x044:',
+for i in range(7):
+  print '0x%08x' % getLongLE( m, 0x44+i*4 ),
+print
+updater1total = getLongLE( m, 0x60 )
+print '0x060: 0x%x' % updater1total 
+firmwareLen = getLongLE( m, 0x64 )
+print '0x064: firmware length = 0x%x' % firmwareLen
+if (firmwareLen + firmware) != efileLen:
+  print 'error : (firmwareLen + firmware) != efileLen'
+print '0x068: updater1 hmac-sha1 = %s' % hexlify( m[ 0x68:0x68+20 ] ) 
+print '0x088: firmware hmac-sha1 = %s' % hexlify( m[ 0x88:0x88+20 ] ) 
+print '---updater1 header---'
+updater1len = getLongLE( m, updater1header )
+print '0x%03x: updater1 length = 0x%x. starts at 0x%x' % (updater1header, updater1len, updater1)
+print '0x%03x: 0x%x' % ( updater1header + 4, getLongLE( m, updater1header+4 ))
+print '0x%03x: 0x%x' % ( updater1header + 8, getLongLE( m, updater1header+8 ))
+xorSeed = getLongLE( m, updater1header + 0xc )
+print '0x%03x: xor seed value = 0x%x' % ( updater1header + 0xc, xorSeed)
+if getLongLE( m, 0xc0 )!=0 or options.zeros:
+  print '0x0c0: %s' % hexlify( m[ 0x0c0:0x0d0 ] ) 
+  print '0x0d0: %s' % hexlify( m[ 0x0d0:0x0f0 ] ) 
+  print '0x0f0: %s' % hexlify( m[ 0x0f0:0x100 ] ) 
+  print '0x100: %s' % hexlify( m[ 0x100:0x120 ] ) 
+print '0x%03x: --- updater1 (ciphered) ---' % updater1
+prefix = '{0:04x}'.format(model & 0xffff) + "_" + m[0x10]+m[0x12]+m[0x14] 
+if options.extract:
+  decipher_updater( xorSeed, updater1, updater1len, prefix+'_updater1_.bin')
+
+if ctypes.c_int32(updater2header).value!=-1:
+  print '---updater2 header---'
+  model2 = getLongLE( m, updater2header )
+  print '0x%03x: (+0x000), modelId = 0x%08x,' % (updater2header, model2),
+  os2, modelName2 = getModel( model2 )
+  if (os2 != None):
+    print '(%s, %s)' % (modelName2, osName[os2] )
+  print '0x%03x: (+0x010), version = %s' % ( updater2header+0x10, m[updater2header+0x10:updater2header+0x10+5] )
+  fsum2 = getLongLE( m, updater2header+0x20 )
+  print '0x%03x: (+0x020), checksum? = 0x%08x' %  ( updater2header+0x20, fsum2 )
+  print '0x%03x: (+0x024), 0x%x' %  ( updater2header+0x24, getLongLE( m, updater2header+0x24 ) )
+  print '0x%03x: (+0x028), 0x%x' %  ( updater2header+0x28, getLongLE( m, updater2header+0x28 ) )
+  print '0x%03x: (+0x02c),' % (updater2header+0x2c),
+  for i in range (3):
+    print '%x' %  ( getLongLE( m, updater2header+0x2c+i*4 ) ),
+  print
+  print '0x%03x: (+0x038), updater length (including header) = 0x%x. starts at 0x%x' \
+   %  ( updater2header+0x38, getLongLE( m, updater2header+0x38 ), updater2header )
+  if options.zeros:
+    print '0x%03x: (+0x03c), %s' % ( updater2header+0x3c, hexlify( m[ updater2header+0x3c:updater2header+0x3c+0x30 ] ) )
+    print '0x%03x: (+0x06c), %s' % ( updater2header+0x6c, hexlify( m[ updater2header+0x6c:updater2header+0x6c+0x30 ] ) )
+    print '0x%03x: (+0x09c), %s' % ( updater2header+0x9c, hexlify( m[ updater2header+0x9c:updater2header+0x9c+0x14 ] ) )
+  updater2len = getLongLE( m, updater2header+0xb0 )
+  updater2 = updater2header+0x120
+  print '0x%03x: (+0x0b0), updater length = 0x%x. starts at 0x%x' %  ( updater2header+0xb0, updater2len, updater2 )
+  print '0x%03x: (+0x0b4), 0x%x' %  ( updater2header+0xb4, getLongLE( m, updater2header+0xb4 ) )
+  print '0x%03x: (+0x0b8), 0x%x' %  ( updater2header+0xb8, getLongLE( m, updater2header+0xb8 ) )
+  xorSeed2 = getLongLE( m, updater2header+0xbc )
+  print '0x%03x: (+0x0bc), xor seed value = 0x%x' %  ( updater2+0xbc, xorSeed2 )
+  if options.zeros:
+    print '0x%03x: (+0x0c0), %s' % ( updater2header+0xc0, hexlify( m[ updater2header+0xc0:updater2header+0xe0 ] ) )
+    print '0x%03x: (+0x0e0), %s' % ( updater2header+0xe0, hexlify( m[ updater2header+0xe0:updater2header+0x100 ] ) )
+    print '0x%03x: (+0x100), %s' % ( updater2header+0x100, hexlify( m[ updater2header+0x100:updater2header+0x120 ] ) )
+  print '0x%03x: (+0x120), --- updater2 (ciphered) ---' % (updater2)
+  if options.extract:
+    decipher_updater( xorSeed2, updater2, updater2len, prefix+'_updater2_.bin')
+
+print '---firmware header---'
+print '0x%06x: (+0x000), offset to decryption data = 0x%x' % ( firmware,  getLongLE( m, firmware ))
+print '0x%06x: (+0x004), offset to encrypted data = 0x%x. starts at 0x%x' % ( firmware+4,  getLongLE( m, firmware+4 ), firmware)
+print '0x%06x: (+0x008), total firmware length (including header) = 0x%x. starts at 0x%x' % ( firmware+8,  getLongLE( m, firmware+8 ), firmware)
+print '-'
+print '0x%06x: (+0x00c), firmware length (encrypted part) = 0x%x. starts at 0x%x' % ( firmware+0xc,  getLongLE( m, firmware+0xc ), firmware+0x7c)
+print '0x%06x: (+0x010), 0x%08x' % ( firmware+0x10,  getLongLE( m, firmware+0x10 ))
+print '0x%06x: (+0x014), 0x%x' % ( firmware+0x14,  getLongLE( m, firmware+0x14 ))
+print '0x%06x: (+0x018), 0x%08x' % ( firmware+0x18,  getLongLE( m, firmware+0x18 ))
+print '0x%06x: (+0x01c), %s' % ( firmware+0x1c, hexlify( m[ firmware+0x1c:firmware+0x1c+0x10 ] ) )
+print '0x%06x: (+0x02c), %s' % ( firmware+0x2c, hexlify( m[ firmware+0x2c:firmware+0x2c+0x20 ] ) )
+print '0x%06x: (+0x04c), %s' % ( firmware+0x4c, hexlify( m[ firmware+0x4c:firmware+0x4c+0x10 ] ) )
+print '0x%06x: (+0x05c), %s' % ( firmware+0x5c, hexlify( m[ firmware+0x5c:firmware+0x5c+0x20 ] ) )
+print '---firmware (encrypted)---'
+print '0x%06x: (+0x07c)' % ( firmware+0x7c )

File contrib/indy/gui_bitmaps.py

+#parses gui bitmaps
+
+import sys
+from struct import unpack, pack
+from binascii import unhexlify, hexlify
+import zlib
+import Image
+import array
+from optparse import OptionParser
+
+defaultPalette=[
+"ffffff","ebebeb","000000","000000","a33800","20bbd9","009900","01ad01","ea0001","0042d4","b9bb8c","1c237e","c80000","0000a8","c9009a","d1c000",
+"e800e8","d95e4c","003e4b","e76d00","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","e800e8",
+"e800e8","e800e8","e800e8","e800e8","e800e8","e800e8","090909","121212","1b1b1b","242424","292929","2e2e2e","323232","373737","3b3b3b","404040",
+"454545","494949","525252","5c5c5c","656565","6e6e6e","757575","777777","7c7c7c","818181","858585","8a8a8a","8e8e8e","939393","989898","9c9c9c",
+"a1a1a1","a5a5a5","aaaaaa","afafaf","b3b3b3","b8b8b8","bcbcbc","c1c1c1","c6c6c6","cacaca","cfcfcf","d3d3d3","d8d8d8","dddddd","e1e1e1","e6e6e6",
+"dcc2c3","cf9496","c16566","b13537","a3070a","a00000","9c0001","960002","8c0001","840000","7e0001","770101","6a0000","5c0100","4c0002","3e0001",
+"310101","240000","160002","6c2427","662223","5f1f20","591d1d","511b1b","491919","411516","381112","311112","2a0d0f","270d0e","e90101","c80000",
+"c1d4e3","94bbdc","66a4d5","398cd0","1076ca","0870c9","066bbd","0666ba","0665b5","065ea8","04579b","065192","044a85","064379","043c6b","05345e",
+"02294a","021e36","021526","346188","346188","305b7e","284b6b","24435f","203c54","1b344a","1a2f40","172a39","132434","11212e","0edce9","0cb3e8",
+"ddd7c1","cfc194","c4ac64","b99735","ad8106","ac7f02","a47700","9c7301","926c01","8c6700","856301","795a00","6c4f01","5e4502","503c00","483701",
+"3c2e01","2c2101","1e1802","715e26","6c5b25","665623","5e5021","57481f","4e401b","433818","392f14","2e2812","25200d","1c190a","e9e700","e6b800",
+"dfcfc2","d3af95","c78d65","bc6d35","af4e07","ae4901","a84700","a44501","984000","8d3d00","833801","793300","6d2f00","5d2800","502201","471e00",
+"3e1a00","2f1401","1c0c00","734828","6a4123","613c22","53331c","492e1b","3e2717","342112","2e1c10","25170e","180f0a","0d0a05","e88d00","e76d00",
+"c0d3c0","95be96","67a566","368c35","097609","017101","016e01","176800","181998","181998","181998","5b1997","484455","00205d","181998","001998",
+"002601","011e00","001800","1a4c1b","174618","154217","143d15","123413","112e10","0d270c","0a200b","081909","050f07","020403","01df02","01b401",
+"191d26","1d212c","1d242e","212733","232b38","262e3b","283140","2a3342","2b3445","2c3848","2d3949","2d3949","364356","41516a","4f607e","5a6e8f" ]
+
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+def getLongSE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+
+def rleDecompress2(off):
+   offset = off
+   times = ord(m[offset+1])
+   data = array.array('B')
+   while times > 0:
+      for i in range(times):
+          data.append(ord(m[offset]))
+      offset = offset+2
+      times = ord(m[offset+1])
+   return data
+
+parser = OptionParser(usage="usage: %prog [options] filename")
+parser.add_option("-x", "--extract", action="store_true", dest="extract", default=False, help="extract bitmaps")
+parser.add_option("-g", "--grey", action="store_true", dest="grey", default=False, help="grey palette")
+(options, args) = parser.parse_args()
+
+f = open(args[0],'rb')
+m = f.read()
+f.close()
+
+"""
+0x08 offset table + compressed bitmaps
+0x10 Font CanonGothic + Monospace
+0x18 offset strings table + strings 
+0x20 offset tables + menu something
+0x28 
+0x30
+"""
+palette = []
+for i in range(256):
+     if options.grey:
+         color = (i, i, i)
+     else:
+         color = ( ord(unhexlify(defaultPalette[i][:2])), ord(unhexlify(defaultPalette[i][2:4])), ord(unhexlify(defaultPalette[i][4:])) )
+     palette.extend(color) 
+assert len(palette) == 768
+
+#parses data directory
+nb_records = getLongLE(m, 0) 
+filesize = getLongLE(m, 4)
+print "nb_records=%d, filesize= 0x%08x" % (nb_records, filesize)
+for o in range(8, 8+nb_records*8, 8):
+    offset = getLongLE(m, o)
+    length = getLongLE(m, o+4)
+    if o==8:
+        bitmaps_offset = offset
+    print '0x%08x: 0x%08x 0x%08x' % (o , offset, length)
+bitmaps_table= bitmaps_offset+4
+
+print
+nb = getLongLE(m, bitmaps_offset)
+print '0x%08x: nb_bitmaps = 0x%08x ' % (bitmaps_offset , nb)
+
+prev = 0
+for o in range(bitmaps_table, bitmaps_table+nb*8, 8):
+    val = getLongLE(m, o)
+    val2 = getLongLE(m, o+4)
+    decomp =  getLongLE(m, val2+bitmaps_offset+4)
+    w = getLongSE(m, val2+bitmaps_offset)
+    h = getLongSE(m, val2+bitmaps_offset+2)
+    if prev>0: 
+        delta = val2-prev
+    else:
+        delta = 0
+    print '0x%08x: 0x%08x 0x%08x delta=0x%04x, %3d %3d %d' % (o , val, val2+bitmaps_offset, delta, 
+        h, w, decomp, ),
+    filename = 'bitmap_'+'{0:08x}'.format(val)+'_'+'{0:d}'.format(w)+'x'+'{0:d}'.format(h)+'.bmp'
+    if decomp==5:
+        d = zlib.decompress(m[val2+bitmaps_offset +12:])
+        print '%04x %s' % ( getLongSE(m, val2+bitmaps_offset+8), hexlify(m[val2+bitmaps_offset+10:val2+bitmaps_offset+20]) ),
+        print len(d)
+        im = Image.frombuffer('P',(w,h), d, 'raw', 'P', 0, 1)
+        im.putpalette(palette)
+        if options.extract:
+            im.save(filename)
+    elif decomp==7:
+        d = zlib.decompress(m[val2+bitmaps_offset +12:])
+        print '%04x %s' % ( getLongSE(m, val2+bitmaps_offset+8), hexlify(m[val2+bitmaps_offset+10:val2+bitmaps_offset+20]) ),
+        print len(d)
+        im = Image.frombuffer('1',(w,h), d, 'raw', '1', 0, 1)
+        if options.extract:
+            im.save(filename)
+    elif decomp==2:
+        d = rleDecompress2(val2+bitmaps_offset +8)
+        print hexlify(m[val2+bitmaps_offset+8:val2+bitmaps_offset+20]),   
+        print len(d)
+        im = Image.frombuffer('P',(w,h), d, 'raw', 'P', 0, 1)
+        im.putpalette(palette)
+        if options.extract:
+            im.save(filename)
+    elif decomp==3:
+        d = rleDecompress2(val2+bitmaps_offset +8)
+        print hexlify(m[val2+bitmaps_offset+8:val2+bitmaps_offset+20]),   
+        im = Image.frombuffer('P',(h,w), d, 'raw', 'P', 0, 1)
+        if options.extract>0:
+            im.save(filename)
+        print len(d)
+    elif decomp==0:   #no compression
+        print hexlify(m[val2+bitmaps_offset+8:val2+bitmaps_offset+20]),   
+        if w%8 != 0:
+            w1=(w/8)+1
+        else:
+            w1=w/8
+        d = m[val2+bitmaps_offset +8:val2+bitmaps_offset +8+(w1*h)]
+        im = Image.frombuffer('1',(w,h), d, 'raw', '1', 0, 1)
+        if options.extract:
+            im.save(filename)
+        print 8+(w1*h)
+    else:
+        print hexlify(m[val2+bitmaps_offset+8:val2+bitmaps_offset+20])   
+    prev = val2
+    
+    

File contrib/indy/gui_strings.py

+import sys
+from struct import unpack
+from binascii import unhexlify, hexlify
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+#600d 1.0.1 0xff800000 base
+offset = 0x10f7ac
+offset3 = 0x1ed720
+
+#60d 1.0.9 ?   0xff800000 base
+#offset = 0x209c4
+#offset3 = 0xa611c
+
+#550d 1.0.8 0xff000000 base
+offset = 0x6ca90c
+offset3 = 0x739678
+
+#7d 1.2.3  0xff000000 base
+offset = 0x68bccc
+offset3 = 0x747300
+
+
+f = open(sys.argv[1],'rb')
+m = f.read()
+f.close()
+
+offset = getLongLE(m, 0x18)
+dialog_offset = getLongLE(m, 0x20)
+print '0x%08x: strings_data at 0x%08x' % (0x18, offset)
+
+nb_lang = getLongLE(m, offset+4)
+print '0x%08x: nb_lang=0x%08x' % (offset+4, nb_lang) 
+nb_offset = getLongLE(m, offset+8)
+print '0x%08x: nb_offset=0x%08x' % (offset+8, nb_offset )
+start = offset+12
+end = (nb_offset+1)*4 + offset+12
+print ' end=0x%08x' % (end)
+
+#print '0x%08x: 0x%08x' % (offset+8 , start )
+prev = 0
+i=0
+for o in range(start, end, 4):
+    val = getLongLE(m, o)
+    end = m.find('\0', offset+4+val)
+    print '0x%08x: 0x%04x 0x%08x (delta=0x%08x) 0x%x %s' % (o , i, val, val-prev, offset+val, m[offset+4+val:end])
+    prev = val
+    i=i+1
+last_offset = offset+val
+print '0x%08x:' % (last_offset )
+
+print '0x%08x: dialogs_data at 0x%08x' % (0x20, dialog_offset)
+
+#no 5dm2
+nb = getLongLE(m, dialog_offset+4)
+print '0x%08x: nb_dialogs = 0x%08x' % (dialog_offset+4 , nb )
+# 5dm2
+#nb = getLongLE(m, dialog_offset)
+print '0x%08x: nb_dialogs = 0x%08x' % (dialog_offset , nb )
+
+prev = 0
+for n in range(nb):
+    o = dialog_offset+4+n*8
+    val = getLongLE(m, o+4)
+    print '0x%08x: 0x%08x 0x%08x delta=0x%04x 0x%x %s' % (o, getLongLE(m, o), val, val-prev, dialog_offset+val, hexlify(m[dialog_offset+val:dialog_offset+val+300]) )
+    prev = val    

File contrib/indy/ofir_tool.py

+# ofir_tool.py 
+# Copyright (C) 2010 Arm.Indy, arm.indiana at google mail
+# decode fir updates for 5D, 30D and 400D
+
+# based on eos_tools_v11\dissect_fw2_5d and eos_tools_v11\dissect_fw2
+# see eos_tools_v11.tar, http://chdk.setepontos.com/index.php/topic,111.msg11400.html#msg11400
+"""
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+ 
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the
+Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor,
+Boston, MA  02110-1301, USA.
+"""
+import os
+import sys
+import array
+from struct import unpack
+import ctypes
+from binascii import hexlify, unhexlify
+from optparse import OptionParser
+
+version_id = "0.6 for 5D/30D/400D (11Nov2010)"
+# based on a previous tool in C, dec 2009
+
+# for 300D and 10D, see :
+# - Alex Berstein 300d: http://wiki.alexbernstein.com/FirmwareDecrypterUnpacker  
+# - module_list.cpp, to extract files from 300d firmware (http://iiepwie.narod.ru/) 
+
+# decoding tables for 20D, 20Da, 350D, 30D, 5D and 400D
+# found by Alex Berstein (30May2005): http://tech.groups.yahoo.com/group/canondigicamhacking/message/5712
+# taken from eos_tools_v11/decrypt_fw1/20D_table.h
+t512 = [ 0x53, 0xca, 0x81, 0x0a, 0x4d, 0xe1, 0xb2, 0x7f, 0x43, 0xf1, 0x95, 0xf6, 0xe9, 0x0d, 0x6c, 0x3c,
+ 0xb8, 0xaa, 0x79, 0xd8, 0x40, 0xcd, 0xb2, 0xed,  0x00, 0xf9, 0xd1, 0xd0, 0x14, 0x1c, 0x9a, 0x2c,
+ 0xf0, 0xf4, 0xf3, 0x1f, 0xb8, 0x0d, 0x99, 0xc7,  0x8c, 0xd8, 0xf3, 0x67, 0xe4, 0xf5, 0x2c, 0x32,
+ 0x5e, 0xd8, 0xe2, 0x72, 0xd4, 0x8f, 0x1d, 0x95, 0x00, 0x8d, 0xdc, 0x58, 0xf6, 0xde, 0xa5, 0x3c,
+ 0x7e, 0xe8, 0x46, 0xc7, 0x77, 0x20, 0x45, 0x18, 0x32, 0x33, 0xc7, 0xd5, 0x46, 0x3f, 0x50, 0x06,
+ 0x2d, 0xb8, 0xc4, 0x80, 0xa3, 0x4a, 0xed, 0x3f, 0xbf, 0x38, 0xad, 0xd2, 0x0c, 0xc3, 0x8e, 0xa4,
+ 0x29, 0x69, 0x90, 0xbe, 0xdb, 0x1c, 0x21, 0x75, 0x36, 0x93, 0x0b, 0xaf, 0xc7, 0xad, 0x97, 0xc5,
+ 0xd7, 0xa2, 0x30, 0x12, 0xfd, 0x40, 0x30, 0x9f, 0xa6, 0x18, 0xff, 0xdb, 0xbd, 0xfa, 0x9d, 0xbc,
+ 0x97, 0x09, 0x94, 0x53, 0x80, 0x86, 0x81, 0xb8, 0x2a, 0xdd, 0x6a, 0x31, 0x32, 0x8e, 0x7e, 0xe5,
+ 0xe3, 0x84, 0x13, 0x5e, 0x6e, 0xc7, 0x06, 0x1d, 0x0b, 0xff, 0x83, 0x75, 0x2d, 0xa4, 0xa3, 0xfb,
+ 0xc4, 0x34, 0x06, 0xdc, 0xd4, 0x2b, 0x65, 0xee, 0xa7, 0x79, 0x50, 0xf6, 0xbc, 0x32, 0xe1, 0x3c,
+ 0x39, 0x41, 0x0c, 0xc0, 0x48, 0x90, 0x42, 0x3c, 0xa7, 0xb6, 0x74, 0x3c, 0xdd, 0x6a, 0x5c, 0x8c,
+ 0x17, 0xf6, 0x84, 0x73, 0x01, 0x0c, 0x05, 0xa2, 0xdf, 0x1d, 0x40, 0xa2, 0xbd, 0xe9, 0x63, 0xaf,
+ 0xd4, 0xee, 0xcd, 0xf9, 0x18, 0x01, 0x95, 0x89, 0xdd, 0x8a, 0xac, 0x79, 0x26, 0x78, 0xed, 0x63,
+ 0xd0, 0x11, 0x60, 0xc9, 0xea, 0xd7, 0x16, 0xce, 0x79, 0x83, 0x2c, 0xb1, 0x5b, 0xf8, 0xf3, 0x98,
+ 0x97, 0x61, 0x88, 0x02, 0x2b, 0xe9, 0x90, 0xeb, 0xf5, 0x15, 0x10, 0x0b, 0xf9, 0x11, 0x3c, 0x31,
+ 0x2b, 0x44, 0x27, 0x1f, 0xdd, 0x26, 0x7b, 0x8e, 0x84, 0x97, 0x6b, 0x72, 0x8d, 0x0a, 0xc0, 0x35,
+ 0xac, 0x75, 0x4d, 0x81, 0xad, 0x4f, 0x4c, 0xa1, 0x89, 0x72, 0x2d, 0xa0, 0xa6, 0x10, 0x23, 0x10,
+ 0x99, 0xd7, 0x10, 0x46, 0x9a, 0x63, 0xed, 0x71, 0x8a, 0x5b, 0x46, 0x7e, 0x09, 0x82, 0x29, 0x4b,
+ 0x6d, 0x44, 0x1b, 0x2b, 0xed, 0x21, 0x48, 0xff, 0xdf, 0x17, 0xbf, 0x69, 0x95, 0xd8, 0x9f, 0x7f,
+ 0x4a, 0x11, 0x29, 0x65, 0x4e, 0x9d, 0xdf, 0x8f, 0x31, 0x84, 0x21, 0x04, 0xbf, 0xe7, 0x31, 0xaf,
+ 0x51, 0x9a, 0x94, 0x9b, 0x0c, 0x70, 0xaf, 0x48, 0xc0, 0x1f, 0x3e, 0x41, 0xbb, 0x66, 0xe7, 0xcf,
+ 0x37, 0xc5, 0x96, 0x35, 0xb2, 0x32, 0x5e, 0x9e, 0xfc, 0xb1, 0x0f, 0xcc, 0xc1, 0x06, 0xfe, 0xcb,
+ 0x91, 0xe4, 0xc9, 0x6e, 0xcc, 0x17, 0x79, 0x29, 0x40, 0x20, 0x60, 0x3f, 0xe5, 0x45, 0x4d, 0x30,
+ 0x53, 0x29, 0x45, 0x5f, 0x47, 0x23, 0xb0, 0x12, 0xd2, 0xbb, 0x7f, 0x2b, 0x0a, 0x51, 0xa5, 0xe0,
+ 0x46, 0x97, 0xff, 0x60, 0x9e, 0x30, 0x36, 0x22, 0xf5, 0x8b, 0x63, 0xdb, 0xeb, 0xae, 0xe7, 0x08,
+ 0xb0, 0x0d, 0xd0, 0x76, 0x85, 0x72, 0xdf, 0x0b, 0xd9, 0x10, 0xc6, 0x81, 0x89, 0x35, 0x5b, 0xa6,
+ 0xf5, 0x9d, 0x56, 0xc8, 0x3b, 0xf8, 0x1e, 0x62, 0xcd, 0x4d, 0x8b, 0xa7, 0x74, 0xeb, 0x8d, 0x56,
+ 0xfa, 0x5c, 0xa3, 0x94, 0x39, 0xfc, 0x70, 0xc7, 0xc0, 0x80, 0x14, 0xad, 0x33, 0xb6, 0x08, 0x6f,
+ 0x63, 0x8b, 0x9c, 0x8f, 0x24, 0x4c, 0x91, 0xf6, 0x01, 0x0e, 0x50, 0xe2, 0x14, 0x37, 0x8a, 0xa2,
+ 0x18, 0x2c, 0x3b, 0x93, 0x96, 0x0d, 0xe2, 0xdf, 0xa0, 0x61, 0x65, 0x4d, 0x1b, 0xb6, 0x02, 0x6d,
+ 0x04, 0x08, 0x31, 0x58, 0x7d, 0xa6, 0x76, 0xb5, 0x61, 0x05, 0xb5, 0xc5, 0xdd, 0x06, 0xa7, 0x30  ]
+t513 = [ 0xdb, 0x87, 0x6c, 0xb6, 0xcf, 0x08, 0x5b, 0x3c, 0x2c, 0x16, 0x42, 0x6c, 0x5b, 0x58, 0x20, 0x6e,
+ 0xfc, 0xbb, 0x25, 0xa9, 0xd3, 0x1f, 0x45, 0x12, 0x0e, 0xa9, 0xd7, 0x2b, 0xdd, 0x5f, 0xf5, 0xcd,
+ 0xad, 0x00, 0xeb, 0xa1, 0xf9, 0x00, 0x2a, 0x3c, 0x8c, 0xda, 0x7c, 0xdb, 0x25, 0x05, 0xfb, 0x90,
+ 0xf6, 0xda, 0xdc, 0xd9, 0x76, 0x24, 0x35, 0x59, 0x13, 0xeb, 0x69, 0xee, 0x43, 0x5f, 0x4d, 0x79,
+ 0x15, 0xbd, 0x8b, 0xd5, 0xf9, 0x06, 0x08, 0xbb, 0xf0, 0x92, 0x36, 0xa6, 0x06, 0xc4, 0xf4, 0x90,
+ 0xa4, 0x20, 0x4d, 0x8e, 0xc6, 0x7a, 0xe3, 0xd7, 0x9d, 0x5a, 0x61, 0xb1, 0xbd, 0x94, 0x2e, 0x52,
+ 0x02, 0x73, 0xa3, 0x26, 0x45, 0xfe, 0x54, 0xf7, 0x4f, 0x7a, 0xc4, 0xa4, 0x79, 0xcf, 0xbb, 0x8f,
+ 0x99, 0xfe, 0x4d, 0x7b, 0x98, 0xed, 0x45, 0x46, 0xce, 0x20, 0xa3, 0x3a, 0x58, 0x0d, 0x36, 0x99,
+ 0x44, 0x7b, 0x42, 0x8e, 0x55, 0x37, 0x67, 0xda, 0xf8, 0x37, 0x3d, 0x71, 0x52, 0xfd, 0xe5, 0xdf,
+ 0xb5, 0x19, 0x37, 0x91, 0x61, 0xe8, 0x5a, 0xa2, 0x29, 0xce, 0x5e, 0x59, 0x71, 0x39, 0xf3, 0x5e,
+ 0xb6, 0x0c, 0x2d, 0x53, 0x86, 0x9f, 0xcc, 0x16, 0x73, 0xd1, 0x6d, 0x81, 0xe9, 0xfc, 0x25, 0x48,
+ 0x57, 0x89, 0xe4, 0x10, 0xd4, 0x5a, 0x32, 0xf8, 0xc8, 0x01, 0x44, 0xcb, 0x92, 0xb4, 0x84, 0x91,
+ 0x80, 0xcd, 0xfc, 0x42, 0xec, 0xec, 0x13, 0x6e, 0x28, 0x6e, 0x18, 0x46, 0x9f, 0xaa, 0xef, 0x95,
+ 0xb6, 0x42, 0xa2, 0xab, 0x9a, 0x16, 0xce, 0x84, 0xc4, 0xd0, 0x96, 0x52, 0xd2, 0x95, 0x05, 0x18,
+ 0xa9, 0x57, 0xb9, 0xae, 0x54, 0xc8, 0xe3, 0x27, 0x4c, 0x7f, 0x38, 0xb0, 0x66, 0xf7, 0x06, 0xa4,
+ 0xbf, 0xa0, 0xe1, 0xcc, 0xec, 0xc5, 0x35, 0x01, 0x4b, 0x37, 0x1d, 0x9b, 0x8d, 0x2a, 0x1b, 0xba,
+ 0x28, 0xcb, 0xe2, 0xbe, 0x58, 0x12, 0xb1, 0x55, 0xda, 0x7b, 0xaa, 0x4e, 0xb4, 0x1b, 0x9e, 0x05,
+ 0x84, 0xe6, 0x91, 0x6c, 0x9f, 0x88, 0xe8, 0xf0, 0x15, 0x2b, 0x30, 0x9b, 0x66, 0xf7, 0xf0, 0xcf,
+ 0x0b, 0x81, 0x59, 0xd1, 0x87, 0x06, 0xe8, 0x24, 0x16, 0x2a, 0x97, 0x3c, 0x3a, 0x07, 0x39, 0x75,
+ 0x58, 0xd1, 0xd4, 0x54, 0x33, 0xc0, 0xd9, 0x28, 0xd7, 0x85, 0xcc, 0xf9, 0xa4, 0x0d, 0x76, 0x32,
+ 0xeb, 0xd6, 0x83, 0x99, 0x6a, 0xd7, 0xf3, 0x24, 0xbe, 0x5e, 0xe5, 0xf3, 0xca, 0x71, 0x53, 0x4c,
+ 0x1a, 0xe0, 0xbc, 0x92, 0xcb, 0x4e, 0xaa, 0xdf, 0x98, 0xde, 0x02, 0xf0, 0x5c, 0x7b, 0xda, 0x5b,
+ 0x3f, 0xa9, 0x43, 0x3b, 0x58, 0x7f, 0x90, 0xba, 0x35, 0xdd, 0x3c, 0x79, 0x5d, 0x6c, 0x7b, 0xb6,
+ 0x92, 0xc1, 0x9e, 0xe8, 0xd3, 0x44, 0x04, 0x6c, 0xdb, 0x2e, 0x32, 0x88, 0xe8, 0x4f, 0x33, 0x77,
+ 0xbf, 0xb1, 0xce, 0x1d, 0x65, 0x9d, 0x09, 0x2e, 0x45, 0x5b, 0x54, 0xfd, 0x14, 0x75, 0xdc, 0xd7,
+ 0xc3, 0x9a, 0x69, 0x07, 0x6d, 0x1c, 0xb3, 0x97, 0x86, 0x11, 0xe1, 0x11, 0xab, 0x19, 0xd4, 0x8f,
+ 0xee, 0x30, 0x77, 0x4e, 0xc6, 0xfb, 0xce, 0xdd, 0x74, 0xe0, 0x21, 0xb7, 0xa7, 0x67, 0x84, 0xa1,
+ 0x2e, 0x43, 0x66, 0xbd, 0xc9, 0x8b, 0x6a, 0x84, 0x26, 0x76, 0x17, 0x8c, 0x1c, 0x0d, 0x5b, 0x15,
+ 0xc9, 0x38, 0x27, 0xaf, 0x9e, 0xe1, 0x71, 0x95, 0xb9, 0x50, 0xe7, 0x69, 0x09, 0x38, 0x57, 0x84,
+ 0xfd, 0x41, 0x73, 0x96, 0xef, 0xc3, 0xa9, 0xf1, 0x3b, 0xc2, 0xb3, 0x25, 0x24, 0xb9, 0x95, 0x20,
+ 0x5f, 0x92, 0x74, 0xec, 0x33, 0x87, 0x9e, 0x50, 0xde, 0x25, 0xe0, 0x22, 0x6d, 0xb6, 0x44, 0x6e,
+ 0xd1, 0xe4, 0xe5, 0x75, 0xe1, 0x7e, 0xbe, 0x84, 0x82, 0x8c, 0x4a, 0x3e, 0x2b, 0x97, 0x9f, 0x91,
+ 0x7e ]            
+
+models = [ [ 0x80000213, '5D'], [ 0x80000234, '30D'], [ 0x80000236, '400D / Rebel XTi'] ]
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+def getLongSE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+
+def getModel(id):
+  for i in models:
+    if i[0]==id:
+      return i[1]
+  return None
+
+def xor_decode( start, len ):
+  o512 = 0
+  o513 = 0
+  out = array.array('B', m[start:start+len] )
+  for i in range(len):
+    out[i] =  out[i] ^ t512[o512] ^ t513[o513] 
+    o512 = (o512+1) % 512
+    o513 = (o513+1) % 513
+  return out
+
+def check_xor_decoding( out):
+  if (out[8:16].tostring() == 'Copyrigh') :
+    return True
+  else:
+    return False
+
+def decipher_updater( offset, len, filename):
+  out = xor_decode( offset, len)
+  print ' xor_decoding [0x%x-0x%x]...' % ( offset, offset+len),
+  if check_xor_decoding( out[0x10:] ):
+    print 'OK (%s)' % filename
+    f = open(filename, 'wb')
+    out.tofile(f)
+    f.close()
+  else:
+    print 'KO'
+
+def getData(firmware, offset, modelId):
+  nFiles = getLongLE( m2, offset )
+  print '0x%03x: number of files in the pack = %d' % (offset+0x20, nFiles)
+  tableOffset = getLongLE( m2, offset+4 )
+  print '0x%03x: offset to the file table = 0x%x (from 0x%x)' % (offset+0x20+4, tableOffset, firmware)
+  headerSize = getLongLE( m2, offset+8 )
+  print '0x%03x: header size = 0x%x (from 0x%x). end of header = 0x%x' % (offset+0x20+8, headerSize, firmware, firmware+headerSize)
+  val = getLongLE( m2, offset+0xc )
+  print '0x%03x: size of file table = 0x%x ' % (offset+0x20+0xc, val)
+  val = getLongLE( m2, offset+0x10 )
+  print '0x%03x: size after table = 0x%x' % (offset+0x20+0x10, val )
+  return nFiles, tableOffset, headerSize
+
+#see eos_tools_v11\400D_pack\eospack.c for the 'pack structure'
+def getTable(firmware, modelId, offset, nFiles, headerSize, n):
+  pOffset=0
+  pLength=0
+  if modelId==0x80000213: #5D
+    print '              +-flags-+-offset-+-length-+--name--------------------------+---??---'
+  else:
+    print '              +-flags-+-offset-+-length-+--name--------------------+'
+  for i in range(nFiles):
+    flag = getLongLE( m2, offset )
+    print '0x%06x: 0x%02x 0x%04x ' % (offset+0x20, i+1, flag ),
+    offset = offset+4
+    val = getLongLE( m2, offset )
+    if i+1==n:
+      pOffset = val
+    print '0x%06x' % (val ),
+    val = getLongLE( m2, offset+4 )
+    if i+1==n:
+      pLength = val
+    print '0x%06x' % (val ),
+    end  = m2[ offset+8: ].find("\0")
+    if modelId == 0x80000213:
+      if flag == 1:
+        print '%-32s' % ctypes.c_char_p(m2[ offset+8: offset+8+28]).value, #null terminated string
+        val = getLongLE( m2, offset+36 )
+        print '0x%02x' % (val ),
+      else:
+        print '%-32s' % ctypes.c_char_p(m2[ offset+8: offset+8+32]).value, 
+      val = getLongLE( m2, offset+40 )
+      print '0x%06x' % (val )
+      offset = offset + 44
+    else:
+      print '%-32s' % ctypes.c_char_p(m2[ offset+8: offset+8+28]).value
+      offset = offset + 36
+  print '0x%06x: (+0x%x) end of table, first file' % (offset+0x20, headerSize)
+  return pOffset, pLength
+    
+parser = OptionParser(usage="usage: %prog [options] filename")
+parser.add_option("-c", "--checksum", action="store_true", dest="checksum", default=False, help="verify checksum(s)")
+parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="verbose mode")
+parser.add_option("-x", "--extract", type="int", dest="extract", default=-1, help="extract part")
+(options, args) = parser.parse_args()
+  
+f = open(args[0], 'rb')
+m = f.read()
+fileLen = f.tell()
+f.close()
+
+print 'Fir_tool %s\n' % version_id
+print 'fileLen = 0x%x' % fileLen
+print '---.fir header---'
+modelId = getLongLE( m, 0 )
+print '0x000: modelId = 0x%08x,' % modelId,
+modelName = getModel( modelId )
+if (modelName!=None):
+  print '(%s, VxWorks)' % (modelName)
+else:
+  print 'not supported'
+  sys.exit()
+print '0x010: version = %s' % ( m[0x10:0x10+5] )
+
+print '---ciphered part (xor)---'
+
+prefix = '{0:04x}'.format(modelId & 0xffff) + "_" + m[0x10]+m[0x12]+m[0x14] 
+decipher_updater( 0x20, fileLen-0x20, prefix+'_firmware.bin')
+
+f = open(prefix+'_firmware.bin', 'rb')
+m2 = f.read()
+f.close()
+
+fsum = getLongLE( m2, 0 )
+print '0x020: checksum = 0x%08x' %  fsum 
+if options.checksum:
+  csum = sum( array.array('B', m[ 0:0x20 ]) ) + sum( array.array('B', m2[ 4:fileLen-4 ]) )
+  if fsum != ctypes.c_uint32(~csum).value:
+    print " checksum error csum=0x%x" % (csum)
+  else:
+    print " checksum computing [0x%x-0x%x] is OK!" % (0x0 , fileLen)
+
+updater1 = getLongLE( m2, 4 )
+print '0x024: updater offset = 0x%x' % ( updater1 )
+firmware = getLongLE( m2, 8 )
+print '0x028: firmware pack offset = 0x%x' % firmware
+val = getLongLE( m, 0xc )
+print '0x02c:  = 0x%x' % val
+print '0x030: ---updater---'
+
+print '0x%03x: ---firmware---' % (firmware)
+fsum2 = getLongLE( m2, firmware-0x20 )
+print '0x%03x: (+0x000) firmware checksum = 0x%x' % (firmware, fsum2)
+if options.checksum:
+  csum = sum( array.array('B', m2[ firmware-0x20+4:fileLen-0x20 ]) )
+  if fsum2 != ctypes.c_uint32(~csum).value:
+    print " checksum error csum=0x%x" % (csum)
+  else:
+    print " checksum computing [0x%x-0x%x] is OK!" % (firmware+4 , fileLen)
+if modelId==0x80000213:
+  val = getLongLE( m2, firmware-0x20+4 )
+  print '0x%03x: 0x%x (only with 5D)' % (firmware+4, val)
+  nFiles, tableOffset, headerSize = getData(firmware, firmware-0x20+8, modelId)
+  val = getLongLE( m2, firmware-0x20+tableOffset-4 )
+  print '0x%03x: 0x%x (only with 5D)' % (firmware-0x20+tableOffset-4, val) #dissect_fw2_d5.c is buggy on this!
+else:
+  nFiles, tableOffset, headerSize  = getData(firmware, firmware-0x20+4, modelId)
+
+print '0x%03x: (+0x%03x) files table' % (firmware-0x20+tableOffset, tableOffset)
+pOffset, pLength = getTable(firmware, modelId, firmware-0x20+tableOffset, nFiles, headerSize, options.extract)
+
+if options.extract != -1 and pLength!=0:
+  name = prefix+'_'+'{0:02x}'.format(options.extract)+'.bin'
+  print '\nwriting %s [0x%x-0x%x]. size=0x%x/%d' % (name, pOffset, pOffset+pLength, pLength, pLength)
+  f = open(name, 'wb')
+  f.write( m2[ firmware+pOffset-0x20: firmware+pOffset-0x20+pLength ] )
+  f.close()

File contrib/indy/parse_lens.py

+#parse LENS00.BIN
+
+import sys
+from struct import unpack
+from binascii import unhexlify, hexlify 
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+def getShortLE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+f.close()
+
+base = 0x450
+print 'filesize=%d' % len(m)
+print 'base=%d/0x%x' % (base, base)
+
+i=0x50
+lens_id = 1
+while lens_id > 0:
+  lens_id = getLongLE(m, i) 
+  offset = getLongLE(m, i+4)
+  if lens_id > 0:
+    val = m[base+offset: base+offset+0x370]
+    print 'Lens_id=%4d, offset=0x%x' % (lens_id&0xffff, base+offset) 
+    print ' %d-%d' % ( getShortLE(val,4), getShortLE(val,6) )
+    print hexlify(val[:3]),hexlify(val[3:5]),hexlify(val[5:7]),hexlify(val[7:32])
+    for t in range(32,40,2):
+      print hexlify(val[t:t+2]),
+    print hexlify(val[40:50]),hexlify(val[50:60])
+    for t in range(60, 860, 200): 
+      print hexlify(val[t:t+8])
+      for x in range(t+8, t+192, 12):
+        print hexlify(val[x:x+12]),
+      print
+    print hexlify(val[0x35c:0x370])
+    i = i + 8  

File contrib/indy/parse_lens60.py

+#parse LENS00.BIN
+
+import sys
+from struct import unpack
+from binascii import unhexlify, hexlify 
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+def getShortLE(d, a):
+   return unpack('<H',(d)[a:a+2])[0]
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+f.close()
+
+base = 0x850
+print 'filesize=%d' % len(m)
+print 'base=%d/0x%x' % (base, base)
+
+i=0x50
+lens_id = 1
+while lens_id > 0:
+  lens_id = getLongLE(m, i) 
+  offset = getLongLE(m, i+12)
+  if lens_id > 0:
+    val = m[base+offset: base+offset+0xa90]
+    print 'Lens_id=%4d, offset=0x%x' % (lens_id&0xffff, base+offset) 
+    print ' %d-%d' % ( getShortLE(val,4), getShortLE(val,6) )
+    print hexlify(val[:3]),hexlify(val[3:5]),hexlify(val[5:7]),hexlify(val[7:32])
+    for t in range(32,40,2):
+      print hexlify(val[t:t+2]),
+    print hexlify(val[40:50]),hexlify(val[50:60])
+    for t in range(60, 860, 200): 
+      print hexlify(val[t:t+8])
+      for x in range(t+8, t+192, 12):
+        print hexlify(val[x:x+12]),
+      print
+    print hexlify(val[0x35c:0x370])
+    print hexlify(val[0x37c:0x37c+6]), hexlify(val[0x37c+6:0x38c])
+    for t in range(0x38c,0x38c+12*16,12):
+      print hexlify(val[t:t+12]),
+    print
+    print hexlify(val[0x44c:0x44c+4])
+    print hexlify(val[0x450:0x452]), hexlify(val[0x452:0x454]), hexlify(val[0x454:0x456]),hexlify(val[0x456:0x458]),
+    print hexlify(val[0x458:0x458+10]), hexlify(val[0x462:0x462+10])
+    for t in range(0x46c, 0x46c+4*(8+ 16*24), 8+ 16*24): 
+      print hexlify(val[t:t+8])
+      for x in range(t+8, t+8+16*24, 24):
+        print hexlify(val[x:x+24]),
+      print
+    print hexlify(val[0xa8c:0xa90])  
+    i = i + 16  

File contrib/indy/parse_prop.py

+#parse properties dump file CAMSET00.DAT
+#call SaveCamSetProp (ff019a74) in 550d 109
+
+import sys
+from struct import unpack
+from binascii import unhexlify, hexlify 
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+f.close()
+
+if (len(sys.argv)>2):
+  base = int(sys.argv[2], 16)
+else:
+  base = 0
+
+i = base
+print 'filesize=%d' % len(m)
+print 'offset=%d/0x%x' % (base, base)
+
+while (i+8) < len(m):
+  prop = getLongLE(m, i)
+  length = getLongLE(m, i+4)
+  val = m[i+8: i+8+length]
+  if length > 128:
+     print '0x%05x: 0x%08x, %4d, %s...' % ( i, prop, length, hexlify(val[0:128]) )
+  else:
+     print '0x%05x: 0x%08x, %4d, %s' % ( i, prop, length, hexlify(val) )
+  i = i + length+8
+  

File contrib/indy/parse_tune.py

+#parse TUNE00.BIN
+#call SaveCamSetProp (ff019a74) in 550d 109
+
+import sys
+from struct import unpack
+from binascii import unhexlify, hexlify 
+
+def getLongLE(d, a):
+   return unpack('<L',(d)[a:a+4])[0]
+
+f = open(sys.argv[1], 'rb')
+m = f.read()
+f.close()
+
+if (len(sys.argv)>2):
+  base = int(sys.argv[2], 16)
+else:
+  base = 0
+
+i = base
+print 'filesize=%d/0x%x' % (len(m), len(m))
+print 'offset=%d/0x%x' % (base, base)
+
+prop=0
+while (i+8) < len(m) and prop!=0xffff:
+  prop = getLongLE(m, i)
+  length = getLongLE(m, i+4)-8
+  val = m[i+8: i+8+length]
+  if prop!=0xffff:
+    if length > 128:
+       print '0x%05x: 0x%08x, %4d, %s...' % ( i, prop, length, hexlify(val[0:128]) )
+    else:
+       print '0x%05x: 0x%08x, %4d, %s' % ( i, prop, length, hexlify(val) )
+    i = i + length+8
+  

File contrib/indy/readme.TXT

+This file is a documentation for various python tools written to help reverse engineer Canon DSLR updates.
+Arm.Indy, feb 2013
+
+find_fnt.py          find bitmap fonts in firmware dumps
+find_audio_thr.py    find audio threshold table
+ofir_tool.py         dump firmware updates for 5D, 30D and 400d  
+fir_tool2.py         dump firmware updates for 1Dm3 to 6D
+dump_fir.py          dump or extract decrypted updates content
+gui_strings.py       parse GUI resources and extract strings
+gui_bitmaps.py       parse GUI resources and extract bitmap icons
+dump_srec.py         dump TX19A patches
+parse_prop.py        parses properties stored in flash (CAMSET00.DAT)
+parse_tune.py        parses properties stored in flash (slightly different format: FIX00.BIN, TUNE00.BIN, ...)
+parse_lens.py        parses LENS00.BIN from 550D (with peripherical illunination correction tables only)
+parse_lens60.py      parses LENS00.BIN from 60D (also with chromatic aberration correction)
+
+
+find_fnt.py
+-----------
+
+See http://magiclantern.wikia.com/wiki/Fonts
+
+Usage: find_fnt.py dump_file base_offset
+
+$ python python/find_fnt.py 6d/6D_112_F0000000.bin 0xf0000000
+Find bitmap fonts in Canon DSLR firmwares
+Arm.Indy. based on work by Pel, Trammel Hudson and A1ex
+
+0xf03664ac: FNT
+0xf03664b0: (+0x04) 0xffd8
+0xf03664b2: (+0x06) font_width = 40
+0xf03664b4: (+0x08) charmap_offset = 0x24
+0xf03664b8: (+0x0c) charmap_size = 0x32c4
+0xf03664bc: (+0x10) bitmap_size = 0x8e312
+0xf03664c0: (+0x14) font name = 'HCanonGothic ///'
+0xf03664d0: (+0x24) char_codes[]. 3249 chars
+0xf0369794: (+0x32e8) offsets[]. Last offset value = 0x8e2dc
+0xf036ca58: (+0x65ac) bitmaps[]
+  0xf03fad34: (+0x94888) last bitmap
+  +0x00: bitmap width = 28
+  +0x02: bitmap height = 28
+  +0x04: char width = 36
+  +0x06: X offset = 4
+  +0x08: Y offset = 16
+    bitmap size = 0x70
+...
+
+
+find_audio_thr.py	
+-----------------
+	
+$ python python/find_audio_thr.py 6d/1.1.2/firmware_05.bin
+0x910308
+0x-1
+	
+	
+	
+ofir_tool.py
+------------
+
+See http://chdk.setepontos.com/index.php?topic=5161.0
+
+Usage:
+	
+$ python python/ofir_tool.py firmware/5d000111.fir
+Fir_tool 0.6 for 5D/30D/400D (11Nov2010)
+
+fileLen = 0x4f6424
+---.fir header---
+0x000: modelId = 0x80000213, (5D, VxWorks)
+0x010: version = 1.1.1
+---ciphered part (xor)---
+ xor_decoding [0x20-0x4f6424]... OK (0213_111_firmware.bin)
+0x020: checksum = 0xe1a7fb7b
+0x024: updater offset = 0x30
+0x028: firmware pack offset = 0x16e4d0
+0x02c:  = 0x0
+0x030: ---updater---
+0x16e4d0: ---firmware---
+0x16e4d0: (+0x000) firmware checksum = 0xe9f97565
+0x16e4d4: 0x96e4d4 (only with 5D)
+0x16e4d8: number of files in the pack = 6
+0x16e4dc: offset to the file table = 0x20 (from 0x16e4d0)
+0x16e4e0: header size = 0x140 (from 0x16e4d0). end of header = 0x16e610
+0x16e4e4: size of file table = 0x120
+0x16e4e8: size after table = 0x387e14
+0x16e4cc: 0x1 (only with 5D)
+0x16e4d0: (+0x020) files table
+              +-flags-+-offset-+-length-+--name--------------------------+---??---
+0x16e4f0: 0x01 0x0002  0x000140 0x000042 MPU_FIRMWARE                     0x0001f4
+0x16e520: 0x02 0x0002  0x000182 0x0010a0 MPU_FIRMWARE                     0x00047e
+0x16e550: 0x03 0x0002  0x001222 0x018098 MPU_FIRMWARE                     0x00ae4c
+0x16e580: 0x04 0x0001  0x0192ba 0x35d8c0 --------                         0xf8010000 0x013880
+0x16e5b0: 0x05 0x0001  0x376b7a 0x011398 --------                         0xf8780000 0x000172
+0x16e5e0: 0x06 0x0002  0x387f12 0x000042 MPU_FIRMWARE                     0x0001f4
+0x16e610: (+0x140) end of table, first file
+
+fir_tool2.py
+------------
+
+See http://magiclantern.wikia.com/wiki/Firmware_file
+	
+$ python python/fir_tool2.py firmware/6D000112.FIR
+Fir_tool 0.5 (20Mar2010)
+
+fileLen = 0x12fc3ec
+---.fir header---
+0x000: modelId = 0x80000302, 0x010: version = 1.1.2
+0x020: checksum = 0x68bb5542
+0x024: updater1 header = 0xb0
+0x028: updater1 offset = 0x120
+0x02c: updater2 offset = 0xffffffff
+0x030: firmware offset = 0x1bc2a0
+0x034: 0xffffffff
+0x038: embedded file size = 0x12fc3ec
+0x03c: 0x0
+0x040: sha1 seed = 0x11407eb6
+0x044: 0x00000004 0x00000000 0x00000020 0x00000024 0x00000044 0x000000b0 0x001bc1f0
+0x060: 0x1bc2a0
+0x064: firmware length = 0x114014c
+0x068: updater1 hmac-sha1 = b1c400446e0c8442b5b4b4e1ed0cee96bcf83e16
+0x088: firmware hmac-sha1 = a0cb9878ae9141d123e1c582d23e84a5c8cce716
+---updater1 header---
+0x0b0: updater1 length = 0x1bc180. starts at 0x120
+0x0b4: 0x1bc180
+0x0b8: 0x0
+0x0bc: xor seed value = 0xfbc57cb2
+0x0c0: a55c283bbf4afb159f91bd2f57f34b24
+0x0d0: 7e60b6e8abf349332144460a46e40f5580b8ea28d2e6add5c7640ccd49e1fe63
+0x0f0: 12c74374370185d5b1e7578567a47e42
+0x100: 84b2a1b84fc69f6e1118f410b95fe8ee7366610e5c5b804d511624068fcc90f1
+0x120: --- updater1 (ciphered) ---
+---firmware header---
+0x1bc2a0: (+0x000), offset to decryption data = 0xc
+0x1bc2a4: (+0x004), offset to encrypted data = 0x7c. starts at 0x1bc2a0
+0x1bc2a8: (+0x008), total firmware length (including header) = 0x114014c. starts at 0x1bc2a0
+-
+0x1bc2ac: (+0x00c), firmware length (encrypted part) = 0x11400d0. starts at 0x1bc31c
+0x1bc2b0: (+0x010), 0x011400cc
+0x1bc2b4: (+0x014), 0x0
+0x1bc2b8: (+0x018), 0x37a70ca5
+0x1bc2bc: (+0x01c), 035d7a42d6e68d83966336b70d1bcfd3
+0x1bc2cc: (+0x02c), 52b53cc66e42f23edf74c736aee5d8105cb94cbb78a28213a21c3262eb7a6941
+0x1bc2ec: (+0x04c), b98705d2282574e5029f826d1b04f402
+0x1bc2fc: (+0x05c), 7e02b6a079024faaa54bd0486ebfb69328c17f548dd7c3f07a4570a150afb82f
+---firmware (encrypted)---
+0x1bc31c: (+0x07c)
+
+dump_fir.py
+-----------
+
+See http://magiclantern.wikia.com/wiki/Update_records
+
+$ python python/dump_fir.py -v 6d/1.1.2/0302_112_firmware.bin
+Dump_fir 0.5 (22dec2012)
+
+fileLen = 0x11400d0
+0x000: checksum = 0x979dc27a
+0x004: 0x00000000
+0x008: 0x00000002
+0x00c: 0x00000000
+0x010: nb_record = 0x5
+0x014: table_offset = 0x20
+0x018: record_size = 0x18
+0x01c: size_after = 0x1140034
+0x020: ---patches table---
+      + tag  + foffset  +   size   + moffset  +    ?
+ --------------------------------------------------------
+ 0x01: 0x0200 0x00000098 0x00000000 0x00000000 0x000002bc
+ 0x02: 0x0200 0x00000098 0x00000000 0x00000000 0x0000add4
+ 0x03: 0x0100 0x00000098 0x00095760 0xf00c0000 0x00000bb8
+ 0x04: 0x0100 0x000957f8 0x004138ec 0xf0240000 0x00003a98
+ 0x05: 0x0100 0x004a90e4 0x00c96fe8 0xf80c0000 0x00018a88
+0x098: ---patch#1---
+	
+	
+$ python python/dump_fir.py -x 5 6d/1.1.2/0302_112_firmware.bin
+Dump_fir 0.5 (22dec2012)
+
+fileLen = 0x11400d0
+0x000: checksum = 0x979dc27a
+0x004: 0x00000000
+0x008: 0x00000002
+0x00c: 0x00000000
+0x010: nb_record = 0x5
+0x014: table_offset = 0x20
+0x018: record_size = 0x18
+0x01c: size_after = 0x1140034
+0x020: ---patches table---
+      + tag  + foffset  +   size   + moffset  +    ?
+ --------------------------------------------------------
+ 0x01: 0x0200 0x00000098 0x00000000 0x00000000 0x000002bc
+ 0x02: 0x0200 0x00000098 0x00000000 0x00000000 0x0000add4
+ 0x03: 0x0100 0x00000098 0x00095760 0xf00c0000 0x00000bb8
+ 0x04: 0x0100 0x000957f8 0x004138ec 0xf0240000 0x00003a98
+ 0x05: 0x0100 0x004a90e4 0x00c96fe8 0xf80c0000 0x00018a88
+0x098: ---patch#1---
+writing firmware_05.bin [0x4a90e4-0x11400cc]. size=0xc96fe8/13201384
+	
+gui_strings.py
+--------------
+
+See http://magiclantern.wikia.com/wiki/GUI_Resources
+
+to parse strings from GUI resources (update record 4 in update 2.1.1 of 5dm2):
+	
+python gui_strings.py 5dm2/2.1.1/firmware_04.bin |less
+0x00000018: strings_data at 0x000c8c40
+0x000c8c44: nb_lang=0x00000019
+0x000c8c48: nb_offset=0x00000673
+ end=0x000ca61c
+0x000c8c4c: 0x0000 0x000019d8 (delta=0x000019d8) 0xca618 English
+0x000c8c50: 0x0001 0x00001ab3 (delta=0x000000db) 0xca6f3 English
+0x000c8c54: 0x0002 0x00001bc8 (delta=0x00000115) 0xca808 LEFT
+0x000c8c58: 0x0003 0x00001c46 (delta=0x0000007e) 0xca886 OK
+0x000c8c5c: 0x0004 0x00001caf (delta=0x00000069) 0xca8ef OK
+0x000c8c60: 0x0005 0x00001d21 (delta=0x00000072) 0xca961 Cancel
+0x000c8c64: 0x0006 0x00001e11 (delta=0x000000f0) 0xcaa51 Erase
+0x000c8c68: 0x0007 0x00001edc (delta=0x000000cb) 0xcab1c Quality
+0x000c8c6c: 0x0008 0x00001fe5 (delta=0x00000109) 0xcac25 Beep
+0x000c8c70: 0x0009 0x00002118 (delta=0x00000133) 0xcad58 On
+0x000c8c74: 0x000a 0x000021aa (delta=0x00000092) 0xcadea Off
+0x000c8c78: 0x000b 0x00002238 (delta=0x0000008e) 0xcae78 Shoot w/o card
+0x000c8c7c: 0x000c 0x0000242f (delta=0x000001f7) 0xcb06f On
+0x000c8c80: 0x000d 0x000024be (delta=0x0000008f) 0xcb0fe Off
+0x000c8c84: 0x000e 0x00002558 (delta=0x0000009a) 0xcb198 WB SHIFT/BKT
+0x000c8c88: 0x000f 0x0000271a (delta=0x000001c2) 0xcb35a SHIFT
+0x000c8c8c: 0x0010 0x000027ee (delta=0x000000d4) 0xcb42e BKT
+0x000c8c90: 0x0011 0x000028ab (delta=0x000000bd) 0xcb4eb Clear all
+0x000c8c94: 0x0012 0x00002a11 (delta=0x00000166) 0xcb651 Custom WB
+0x000c8c98: 0x0013 0x00002c2a (delta=0x00000219) 0xcb86a Custom WB regist.
+0x000c8c9c: 0x0014 0x00002e60 (delta=0x00000236) 0xcbaa0 Correct WB may not be obtained
+0x000c8ca0: 0x0015 0x0000320b (delta=0x000003ab) 0xcbe4b with the selected image
+0x000c8ca4: 0x0016 0x0000351e (delta=0x00000313) 0xcc15e Use WB data from this image
+...
+0x000ca604: 0x066e 0x000b51bc (delta=0x000000b5) 0x17ddfc RELEASE
+0x000ca608: 0x066f 0x000b5283 (delta=0x000000c7) 0x17dec3 CF PLAY
+0x000ca60c: 0x0670 0x000b5352 (delta=0x000000cf) 0x17df92 SD PLAY
+0x000ca610: 0x0671 0x000b5421 (delta=0x000000cf) 0x17e061 Fail
+0x000ca614: 0x0672 0x000b549e (delta=0x0000007d) 0x17e0de UNIT
+0x000ca618: 0x0673 0x000b551a (delta=0x0000007c) 0x17e15a
+0x0017e15a:
+0x00000020: dialogs_data at 0x0017e178
+0x0017e17c: nb_dialogs = 0x00000001
+0x0017e178: nb_dialogs = 0x00000001
+0x0017e17c: 0x00000001 0x00000784 delta=0x0784 0x17e8fc 010000000100010002000000434f4d4d4f4e0000000000000200000028000040
+380000000000c0031c0200000000c0031c0200000000000000000000000000000000000001000002444c475f5243200011000202aa00e2006c022800
+0009010401000000000a03040100004001000000010006000c000000434f4d4d4f4e0000000000000000000002000040380000000000d002e0010000
+0000d002e00100000000000000000000000000000000000000000001444c475f524320000100020232001a0128002800000400040000000000090304
+010000400100020332005a0128002800000400040000000000090304010000400100020432009a012800280000040004000000000009030401000040	
+
+
+gui_bitmaps.py
+--------------
+
+python gui_bitmaps.py 5dm2/2.1.1/firmware_04.bin
+nb_records=6, filesize= 0x001c78bc
+0x00000008: 0x00000038 0x0004e93c
+0x00000010: 0x0004e974 0x0007a2cc
+0x00000018: 0x000c8c40 0x000b5538
+0x00000020: 0x0017e178 0x00047f48
+0x00000028: 0x001c60c0 0x00000f68
+0x00000030: 0x001c7028 0x00000894
+
+0x00000038: nb_bitmaps = 0x0000047d
+0x0000003c: 0x10000001 0x00002424 delta=0x0000,  52  26 5 00f3 00091819ed8f41124321 1352
+0x00000044: 0x10000002 0x00002524 delta=0x0100,  48  24 5 00ce 00091819d54f410ec330 1152
+0x0000004c: 0x10000003 0x00002600 delta=0x00dc,  48  24 5 00ce 00091819d54f410ec330 1152
+0x00000054: 0x10000004 0x000026dc delta=0x00dc,  52  26 3 00a9320100323d0101013d01 1352
+0x0000005c: 0x10000005 0x00002758 delta=0x007c,  48  24 3 00cc2902002d2f0134022f01 1152
+0x00000064: 0x10000006 0x000027c8 delta=0x0070,  48  24 3 00cc3202002d3d0101023d01 1152
+0x0000006c: 0x10000007 0x00002838 delta=0x0070,  52  26 5 00c5 00091819c54f5b0ec330 1352
+0x00000074: 0x10000008 0x0000290c delta=0x00d4,  48  24 5 00b5 00091819b58f4b128430 1152
+...
+0x000023f4: 0x00000478 0x0004e3b8 delta=0x006c,  40  20 7 0063 00091819458db1098040 120
+0x000023fc: 0x00000479 0x0004e428 delta=0x0070,  40  40 7 006f 000918196dccb10d0231 200
+0x00002404: 0x0000047a 0x0004e4a4 delta=0x007c, 160 160 7 01c0 00091819ed8fb1b1c320 3200
+0x0000240c: 0x0000047b 0x0004e670 delta=0x01cc, 160 160 7 01db 00091819ed8fb16dc430 3200
+0x00002414: 0x0000047c 0x0004e858 delta=0x01e8,  40  40 7 0084 00091819658e3d0ac330 200
+0x0000241c: 0x0000047d 0x0004e8e8 delta=0x0090,  40  40 7 007e 0009181965ce410ac320 200
+
+to extract icons:
+python gui_bitmaps.py -x 5dm2/2.1.1/firmware_04.bin
+
+
+dump_srec.py
+------------
+See http://magiclantern.wikia.com/wiki/Update_records
+
+$ python dump_srec.py 0218_209_01.bin
+Dump Canon SRec, v0.5
+
+k218_eep.mot 487 bytes,  0x2000-0x2370
+k218_eep.mot 325 bytes,  0x20c-0x7f0
+k218_eep.mot 2 bytes,  0x7f0-0x7f0
+k218_eep.mot 211 bytes,  0x1204-0x1a10
+
+parse_prop.py
+-------------
+
+See http://magiclantern.wikia.com/wiki/Properties
+and https://groups.google.com/forum/?fromgroups=#!topic/ml-devel/-BP-GfnJgT0
+
+$ python parse_prop.py 550d_my/1.0.9/CAMSET00.DAT 
+138048
+0x00000: 0x02000000,    4, ffff0000
+0x0000c: 0x02000001,   16, 312e302e390035342830312900000000
+0x00024: 0x02000002,    4, 00000000
+0x00030: 0x02000003,    4, ffffffff
+0x0003c: 0x02000004,   32, 0000000000000000000000000000000000000000000000000000000000000000
+0x00064: 0x02000005,   16, 342e332e362035342830312900000000
+0x0007c: 0x02000006,    8, 0603040001000054
+0x0008c: 0x02000007,   16, 302e302e300000000000000000000000
+0x000a4: 0x02010000,    4, 8e000000
+0x000b0: 0x02010001,    4, 64000000
+0x000bc: 0x02010002,    4, 64000000
+0x000c8: 0x02010003,    4, 00000000
+0x000d4: 0x02010004,    4, 65260000
+...
+0x18828: 0x02090000,    4, 01000000
+0x18834: 0x0e070000,   64, 2d000072656e7420434c4556590000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000
+0x1887c: 0x0e070001,   64, 2d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000
+0x188c4: 0x0b000000, 36272, d80e1c00300080000000000000000000200040031000000000000000000000000000000000000000000000000000
+0000f600000000000000e700000070030000a0000000e0060000e6000000500a0000b0000000c00d0000ed0000003011000029000000a01400002e00
+0000a0140000e4000000101800009c00000010180000...
+0x2167c: 0x8003001f, 1210, 65284b38000000030000000000330000000168300000010001ff00010000000000010000000000000000000004000
+000010000000000000002000001036598103800000000000000010000000000000000020001000000000001000000000000000000000400000001000
+0000000000000000000010200000100000001ff0600...
+
+parse_tune.py
+-------------
+$ python parse_tune.py 550d_my/1.0.9/FIX00.BIN 0x18
+filesize=262144/0x40000
+offset=24/0x18
+0x00018: 0x00000000,    4, 80000000
+0x00024: 0x00000001,    4, 00000000
+0x00030: 0x00000002,  484, 43616e6f6e20454f53204b69737320583400000000000000000000000000000070020080ea310000e0140000c00d0
+000e0140000bc0d0000e0140000bc0d0000300f0000200a0000200a0000c0060000300f0000200a0000200a0000c006000040140000800d0000800d0
+0000009000000000000000000000000000000000000...
+0x0021c: 0x00000004,  160, 0d009000b3006600a80084000200a800b40075000b00a80082000000c6007b000100a3001d00a300f100560089005
+7009b00540095005b00ae00440081004d0088004d0098004e00ab004e00a3004e00b1004b00bf004a00a4003a00ac003a008f0044008c003800b9003
+d00860045000a0088001a006900ad004300a9006900...
+0x002c4: 0x00000005,    8, 43414e4f4e000000
+0x002d4: 0x00000006,   20, 900005002800030061006100e8030000f3000000
+
+$ python parse_tune.py 550d_my/1.0.9/TUNE00.BIN 0x18
+filesize=1048576/0x100000
+offset=24/0x18
+0x00018: 0x01000000,    4, ffffffff
+0x00024: 0x01000001,    4, feafdcba
+0x00030: 0x01000008,   16, 344b0fef46e9a629f1d304e2eb6484ff
+0x00048: 0x01000002,   16, 56413036323231353200000000000000
+0x00060: 0x01000003,    4, cc100000
+0x0006c: 0x01000004,    4, 420e0000
+0x00078: 0x01000006,    4, 8c219c31
+0x00084: 0x01000007,    8, 494d475f00000000
+0x00094: 0x01000009,    4, 00000000
+0x000a0: 0x0100000a,    4, 00000000
+0x000ac: 0x0100000b,    8, 640cfbb42b200e1a
+0x000bc: 0x0100000c,   20, 5ed9baa83543b5bafce3fbb58db665a08e9ed89b
+0x000d8: 0x01000011,   44, 1a00000056f71b00fb010000dde396005d040200130000200000000000000000499f06ff280000000d000700
+0x0010c: 0x01000012,    4, ffffffff
+0x00118: 0x0100000e,    4, 00000000
+0x00124: 0x0100000f,   16, 0e0c030000000000000000001d000000
+0x0013c: 0x01000010,   32, 43616e6f6e20454f532035353044000000000000000000000000000000000000
+
+$ python 550d/parse_tune.py 550d_my/1.0.9/RASEN00.BIN 0x20018
+filesize=393216/0x60000
+offset=131096/0x20018
+0x20018: 0x05010000,   24, 180000000000000000000000000000000100000001000000
+0x20038: 0x05010001,  544, 000000006c00000001000000c0a80102ffffff0000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000006c00000001000000c0a80102ffffff00...
+0x20260: 0x05010002, 2204, 00000000b8010000c0a801143139322e3136382e312e3230000000000000000000000000000000000000000000000
+000616e6f6e796d6f75730000000000000000000000000000000000000000000000000000007766742d654063616e6f6e2e636f2e6a7000000000000
+0000000000000000000000000002f00000000000000...
+
+$ python 550d/parse_tune.py 550d_my/1.0.9/RING00.BIN 0x18
+filesize=131072/0x20000
+offset=24/0x18
+0x00018: 0x02000000,    4, ffff0000
+0x00024: 0x02000001,   16, 312e302e390035342830312900000000
+0x0003c: 0x02000005,   16, 342e332e362035342830312900000000
+0x00054: 0x02000002,    4, 00000000
+0x00060: 0x02000003,    4, ffffffff
+0x0006c: 0x02000004,   32, 0000000000000000000000000000000000000000000000000000000000000000
+0x00094: 0x02000006,    8, 0603040001000054
+0x000a4: 0x02000007,   16, 302e302e300000000000000000000000
+
+
+parse_lens.py
+-------------
+
+python parse_lens.py 550d/1.0.9/LENS00.BIN
+
+see http://cpn.canon-europe.com/content/education/masterclass/peripheral_illumination_correction.do
+see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html#LensType 
+call sub_ff019f70 in 550d 109
+see https://groups.google.com/forum/?fromgroups=#!searchin/ml-devel/lens00/ml-devel/YLplVVQIhVA/V_VeB85CojwJ
+see https://groups.google.com/forum/?fromgroups=#!searchin/ml-devel/lens00/ml-devel/-BP-GfnJgT0/5MKdruttlnsJ
+
+
+filesize=196608
+base=1104/0x450
+Lens_id= 246, offset=0x450
+ 16-35
+000001 0010 0023 00180100000000000000000000000000000000000000000000
+1000 1400 1900 2300 f30d4d09a60400000000 f502ea055a0ad40bff0f
+1c0028003900e200
+ff1f9c1ff71e18190a140b04 ff1f671fc01d2e19f5165907 ff1f6e1fb51d31193d17050b ff1f711fb61d25192d172a11 ff1faa1fb01e7c18c7137a04 ff1f681fbf1d2e19fa160408 ff1f6e1fb51d32193f17e00b ff1f711fb61d27192e172611 ff1fbf1f841efa177a13af04 ff1f681fbf1d3019fe164908 ff1f6e1fb61d331940173e0c ff1f711fb61d281930172311 ff1fc91f5c1ea2174d13cc04 ff1f671fbf1d341901176e08 ff1f6e1fb61d34194017750c ff1f711fb71d291931172111
+1c0028003900e200
+ff1ff21f781eef183516380b ff1f831f081e2a1a8718f60f ff1f821f041e0d1a50181212 ff1f841f041efc193718a612 ff1fec1f391e21183415f40a ff1f821f091e261a7818bf0f ff1f821f041e0d1a50180212 ff1f841f041efc193618a312 ff1fe81f0c1e9c17ab14b90a ff1f841f081e2a1a8818c00f ff1f821f041e0d1a5018ff11 ff1f841f041efc193718a212 ff1ff01ff31d431749148d0a ff1f841f081e2a1a8818b30f ff1f821f051e0d1a5018fe11 ff1f841f041efc193718a212
+1c0028003900e200
+ff1fd61f561d0c17bc14e10c ff1fa21f8c1e9b1b4b1aad13 ff1fa21f871e861b2e1a9c15 ff1fa31f871e791b181a8115 ff1fce1f221d75160214290c ff1fa31f8c1e9d1b4d1a5313 ff1fa21f871e871b2f1a9615 ff1fa31f871e791b181a8015 ff1fc91fff1c1c169313b90b ff1fa31f8d1e9d1b4e1acf12 ff1fa21f881e881b301aa415 ff1fa31f881e791b181a7e15 ff1fc91fe81cd4153313530b ff1fa31f8d1e9e1b4e1a7e12 ff1fa21f881e881b301a9a15 ff1fa31f871e791b181a7d15
+1c0028003900e200
+ff1f531e471b7a158013390b ff1fbf1f131f1f1d121c1513 ff1fc31f101f261d4a1ca918 ff1fc51f141f2b1d4c1c4019 ff1ffd1dc41ad614c6128a0a ff1fb81f1d1f141dc71b4112 ff1fc31f101f281d4c1c8618 ff1fc51f141f2b1d4b1c3f19 ff1fc81d7a1a791465120f0a ff1fb81f211ff91c9e1bbe11 ff1fc31f111f291d4d1c5518 ff1fc51f141f2b1d4b1c3e19 ff1f9e1d401a36141412b009 ff1fb81f231fef1c8b1b5d11 ff1fc41f111f2a1d4e1c4218 ff1fc51f141f2b1d4b1c3e19
+444444440000000000000000000000001a010000
+Lens_id= 231, offset=0x7c0
+ 17-40
+000001 0011 0028 00180100000000000000000000000000000000000000000000
+1100 1500 1c00 2800 f30d4d09a60400000000 7004df08920cca0eff0f
+280039005000e200
+...
+
+parse_lens60.py
+---------------
+
+python parse_lens60.py 60d/1.0.9/LENS00.BIN
+
+filesize=393216
+base=2128/0x850
+Lens_id= 246, offset=0x850
+ 16-35
+000001 0010 0023 00180100000000000000000000000000000000000000000000
+1000 1400 1900 2300 f30d4d09a60400000000 f502ea055a0ad40bff0f
+1c0028003900e200
+ff1f9c1ff71e18190a140b04 ff1f671fc01d2e19f5165907 ff1f6e1fb51d31193d17050b ff1f711fb61d25192d172a11 ff1faa1fb01e7c18c7137a04 ff1f681fbf1d2e19fa160408 ff1f6e1fb51d32193f17e00b ff1f711fb61d27192e172611 ff1fbf1f841efa177a13af04 ff1f681fbf1d3019fe164908 ff1f6e1fb61d331940173e0c ff1f711fb61d281930172311 ff1fc91f5c1ea2174d13cc04 ff1f671fbf1d341901176e08 ff1f6e1fb61d34194017750c ff1f711fb71d291931172111
+1c0028003900e200
+ff1ff21f781eef183516380b ff1f831f081e2a1a8718f60f ff1f821f041e0d1a50181212 ff1f841f041efc193718a612 ff1fec1f391e21183415f40a ff1f821f091e261a7818bf0f ff1f821f041e0d1a50180212 ff1f841f041efc193618a312 ff1fe81f0c1e9c17ab14b90a ff1f841f081e2a1a8818c00f ff1f821f041e0d1a5018ff11 ff1f841f041efc193718a212 ff1ff01ff31d431749148d0a ff1f841f081e2a1a8818b30f ff1f821f051e0d1a5018fe11 ff1f841f041efc193718a212
+1c0028003900e200
+ff1fd61f561d0c17bc14e10c ff1fa21f8c1e9b1b4b1aad13 ff1fa21f871e861b2e1a9c15 ff1fa31f871e791b181a8115 ff1fce1f221d75160214290c ff1fa31f8c1e9d1b4d1a5313 ff1fa21f871e871b2f1a9615 ff1fa31f871e791b181a8015 ff1fc91fff1c1c169313b90b ff1fa31f8d1e9d1b4e1acf12 ff1fa21f881e881b301aa415 ff1fa31f881e791b181a7e15 ff1fc91fe81cd4153313530b ff1fa31f8d1e9e1b4e1a7e12 ff1fa21f881e881b301a9a15 ff1fa31f871e791b181a7d15
+1c0028003900e200
+ff1f531e471b7a158013390b ff1fbf1f131f1f1d121c1513 ff1fc31f101f261d4a1ca918 ff1fc51f141f2b1d4c1c4019 ff1ffd1dc41ad614c6128a0a ff1fb81f1d1f141dc71b4112 ff1fc31f101f281d4c1c8618 ff1fc51f141f2b1d4b1c3f19 ff1fc81d7a1a791465120f0a ff1fb81f211ff91c9e1bbe11 ff1fc31f111f291d4d1c5518 ff1fc51f141f2b1d4b1c3e19 ff1f9e1d401a36141412b009 ff1fb81f231fef1c8b1b5d11 ff1fc41f111f2a1d4e1c4218 ff1fc51f141f2b1d4b1c3e19
+444444440000000000000000000000001a010000
+a60400000000 7004df08920cca0eff0f
+0840bd3eb73cd33abb392c39 0f40de3e2f3db73beb3a893a 1040f03e773d453cad3b6a3b 1040fc3ea83da73c343c073c f53f263fe53dee3c883c683c fa3f3b3f323e883d603d653d fb3f473f613eea3deb3d0a3e fb3f4f3f813e2e3e4c3e7e3e da3f8c3f173f053f443f873f e43f9c3f403f5a3fc13f1d40 e43fa23f593f903f10407d40 e33fa73f6b3fb63f4840c040 b03fa63fb13f11408c40e840 da3fd83fed3f5d40e7404e41 da3fdb3ff73f744009417741 d93fde3fff3f854021419541
+33333333
+1000 1400 1900 2300 f30d4d09a60400000000 7004df08920cca0eff0f
+1c0039007100e200
+00400040ae3fc541b83f8243923e9346d83cb749763bf74b 00400040c33fce411740fb420c3fcd45373d2149b43ba44b 00400040ca3fc1412c40ba424e3f8245ad3df648503c9c4b 00400040d23fb7413440aa424d3f7245a13de9483c3c914b 004000400d40c94023406b4104408143c73f0746943ff047 004000402a400a4124410941ed40b942c43f5e45ad3e8547 00400040344003415541e8402c418742f13f2a45c53e5447 004000404140f7409441db407d41784231401845ef3e3e47 00400040624017404941f43f3c415a416c407543a43f2245 00400040804089401842e23f4e42d3403d41e6422140b244 004000408e4089405942d33fb742af40b241b24297407444 004000409d407d407b42bf3ff8429b401142a3420a416a44 00400040a7400e400a42b23f60425040b8418741fc408d42 00400040bf404040bc42993f6b43f33fb7421f41d4413142 00400040d6403c400a432b3fcf43823f0d430b4116427842 00400040e34032402143053f0244573f6043f14082427142
+1c0039007100e200
+00400040243f0c42ef3ed643563ecb45773d6a47c13c7d48 00400040443f4342513fb843f13e65452a3efc467d3d1f48 00400040543f4542593f9843113f2445783eaf46f23dcf47 004000404a3f3e42573f8043263f1145a43eb1462d3ee447 00400040e63fe6400940d741f13f1e43a73f4644653f1045 00400040d13f90411f40f9413940ad420740b443cd3f8e44 00400040c93f90416640f341ba4084428c40604345401944 00400040cc3f8b417f40e541f9406842ec403643ba40e443 004000400e402f4097408040e2403641cf40f441a7407d42 00400040ed3fff40fb40cd40bc41dd40c74169419941f541 004000400e4006413e41cf403142c2406b422b415d429f41 0040004016400e415541ce406342ad40b7420441bb426b41 004000403e4009404341ee3f0d420b4044424f403f428b40 004000400d40854064412440a442e13f2543024045433b40 004000403b409d40c24120402943bc3fc143d13fee430740 004000404f40b140df41144055438f3fff439a3f3944d13f
+1c0039007100e200
+00400040d23e02427d3ef843223e2345a13d7b45353d8545 00400040ef3e8542663e3044803e0345db3e4a45273f6045 00400040e23e7c425d3e3a44443e3c45513eb1455e3ee745 00400040d43e7f42473e3b44083e5d45e23d0246c83d5f46 00400040cb3fc240a53fd241b93fbc42e93f384313407343 00400040483fa741603f9742c13fef420140fd421f40fb42 00400040493fc441653fbd42c63f0843024002431d40f142 004000404e3fcd41613fc242c43f00430a40f0422f40d942 00400040ed3f3e402a409b40a640d9401441e9405c41e840 00400040c83f134116406741a6403a411841f8405d41c940 00400040b13f2d4114409841d9405a417941f140dc41a340 00400040a83f49411640b541f7406441b241e94027428f40 00400040ee3f0a408f4007409841fb3f6d42f13ff242eb3f 00400040ee3fc2407740bf40824149407142dc3f1043983f 00400040e73fc9407940ba40a6412c40ba42ac3f74435c3f 00400040e43ff0408f40ec40ce414140e342983f9743293f
+1c0039007100e200
+00400040c03fc5400e3fc041483efc42c93d0144843dab44 00400040fe3ed341a33e3a425f3ebd420f3e9543ce3d5044 00400040e83edd416f3e4243233ef243dd3d1a44a73d1844 00400040ce3e0c42fb3db9438e3da544663dee44583dfb44 00400040c83f5640e93f76400a4099400940c640fe3fe940 004000408b3f0241b03f3b41f23f1e410b4006410d40fd40 00400040633f5641583fef41a33fe941ea3fb04118408141 00400040573f5d411b3f35425b3f4842bf3ff8410c40ab41 00400040f13ff63f1e401540bb40e83f6841893fe441373f 00400040f23f634018406740af4010405b41ae3fd941693f 00400040c73fc440ee3ff1408e4081403841ef3fb041853f 00400040b53fe040df3f24418a40b7403e411c40bc41a93f 00400040fd3f0140a240fa3fbe41433faf424b3e4a438b3d 00400040ee3f0540664000407e41503f8f42603e4b43a53d 00400040f03f3c405040354058417f3f6a42983e2b43ea3d 00400040f33f7340594068406341963f72429c3e3043e33d
+22222222
+Lens_id= 231, offset=0x12e0
+ 17-40
+000001 0011 0028 00180100000000000000000000000000000000000000000000
+1100 1500 1c00 2800 f30d4d09a60400000000 7004df08920cca0eff0f
+280039005000e200
+...
+
+

File picoc/parse.c

     struct ParseState PreState;
     enum LexToken Token;
     
+    extern int script_stop_requested;
+    if (script_stop_requested)
+        ProgramFail(Parser, "User pressed CTRL-C.");
+
     ParserCopy(&PreState, Parser);
     Token = LexGetToken(Parser, &LexerValue, TRUE);
     

File picoc/platform.h

 #endif
 
 #define assert(x)
-#define malloc SmallAlloc
+#define malloc script_malloc
 #define NO_CALLOC
 #define NO_REALLOC
-#define free SmallFree
+#define free script_free
 #define memcpy my_memcpy
 #undef BIG_ENDIAN
 #define PicocPlatformSetExitPoint()

File picoc/platform_ml.c

     msleep(500);
     PicocParse(FileName, SourceStr, strlen(SourceStr), TRUE, FALSE, TRUE);
 
-    free_dma_memory(SourceStr);
+    script_free_dma(SourceStr);
 }
 
 /* mark where to end the program for platforms which require this */

File platform/5D2.212/cfn.c

 #include <dryos.h>
-
+#include <property.h>
 // look on camera menu or review sites to get custom function numbers
 
 int get_htp() { return GetCFnData(1, 3); }
 
 int get_af_star_swap() { return GetCFnData(3, 2); }
 void set_af_star_swap(int value) { SetCFnData(3, 2, value); }
+
+// 5D2 only; other cameras have different offsets, buffer size etc
+#define PROP_AFMA_CFN 0x80010006
+static int8_t afma_buf[0xF];
+#define AFMA_MODE       afma_buf[0x8]