#!/usr/bin/python """ ExifJpegRescuer --------------- By Jamie A. Thom jamie@practicaluseful.com V 0.1 2009-12-19 Released under GPL v3 or later gnu.org/licenses/gpl.html Exif JPEG File rescuer for camera SDs with damaged FAT tables. OK, basically you need to dump an image of your SD card to a file, set the DiskImage variable to the filename of your disk image file To dump an image of your disk do something like this: # sudo dd if=/dev/sda1 of=/home/username/diskimage This'll only spot exif jpegs, nothing else, but if you can work out a reliable byte sequence for the start and end of any other file type and make the appropriate adjustments to checkstart and checkend you could probably use it to find other stuff. """ #--------# # Set Me # #--------# DiskImage='diskimage' #-----------# # Libraries # #-----------# import sys #-----------# # Functions # #-----------# # Returns an array of the supplied array with the first element dropped and the new element appended # Or the array with the new element appended if it is less than 16 entries def popbuffer(bufferin,byte): bufferout=[] if len(bufferin)<16: bufferin.append(byte) return bufferin else: for i in range(1,16): bufferout.append(bufferin[i]) bufferout.append(byte) return bufferout # Checks the supplied buffer for FFD8FFE1 XXXX 457869 which indicates the start of an Exif # Returns 1 if found def checkstart(bufferin): if len(bufferin)==16: if (bufferin[0]=='\xff') and (bufferin[1]=='\xd8') and (bufferin[2]=='\xff') and (bufferin[3]=='\xe1') and (bufferin[6]=='\x45') and (bufferin[7]=='\x78') and (bufferin[8]=='\x69'): print "Found Exif Start!" print mybuffer return 1 else: return 0 else: print "Buffer length too small to check, wait till it's bigger." return 0 # Checks the supplied buffer for FFD9 when the next bit is not FFDB (which is only end of section) # Returns 1 if found def checkend(bufferin): if len(bufferin)==16: if ((bufferin[0]=='\xff') and (bufferin[1]=='\xd9')) and not ((bufferin[2]=='\xff') and (bufferin[3]=='\xdb')): print "Found Exif End!" print mybuffer return 1 else: return 0 else: print "Buffer length too small to check, wait till it's bigger." return 0 # Writes the picture we've gathered down to a file def dumppicture(picture): global piccount outfile="%s.jpg"%piccount piccount+=1 print "Dumping picture...%s" % outfile out = open(outfile,'wb') for i in range(0,len(picture)-13): # The last 13 bytes are the next file or whatever out.write(picture[i]) out.close() print "Done dumping picture." #------# # Main # #------# print "Opening the file..." try: f = open(DiskImage,'rb') except: sys.exit("Failed to open file.") # Variables... mybuffer=[] # Keep the most recent 16 bytes in here for checking against inpicture=0 # Whether we've found a picture at the moment or not (1 or 0) piccount=0 # The picture count for the output filename # Let's go! try: byte=f.read(1) while byte !="": if inpicture ==0: if (checkstart(mybuffer)==1): inpicture=1 mypicture=mybuffer # The picture begins with the current buffer contents else: if (checkend(mybuffer)==1): inpicture=0 dumppicture(mypicture) # Found the end of the pic, write it to disk # Clear down the buffer and put in all the stuff we already gathered mybuffer=[] mybuffer=mypicture[len(mypicture)-13:] mybuffer.append(byte) print "Buffer is now:" print mybuffer mypicture=[] # Clear mypicture ready for the next one. continue # Skip straight to the top of the list in case the buffer is already at the beginning of a new picure. else: mypicture.append(byte) byte = f.read(1) mybuffer=popbuffer(mybuffer,byte) finally: f.close() print "All Done!"