#!/usr/bin/perl -w

use strict;

# This file clumsily extracts the DB's hidden in the iPhone backup files
# Usage: perl -w bkupextract.pl /Users/flip/Library/Application\ Support/MobileSync/Backup/*/*

# Added support for decoding photo files to Mr. Flip's original script
# Tom Saxton, http://www.idleloop.com/

my %seen;
foreach my $filename (@ARGV)
{    
    # Slurp File Contents
    open(FILE, "<$filename") or die "Can't open $filename: $!";
    my $data = do {local $/; binmode FILE; <FILE>};
    close(FILE);

    # skip non-SQLite Files
    my $outfilename;
    my $type;
    my $dataOut = $data;

	# identify the file and use it to name the output and trim the data
    if ($data =~ m|SQLite|)
    {
		my $type = ($data =~ m!([^/]*?)\.(sqlitedb|db)!) ? $1 : 'unknown';
		$seen{$type}++;
		my $outfilename = sprintf "%s_%02d.db", $type, $seen{$type};

		# dump the part between "SQLite format 3" and end
		# FIXME -- is there cruft at end?  I don't know the SQLite format.  Maybe you do?
		$dataOut =~ s/^(.*?SQLite format 3)/SQLite format 3/;
    }
    elsif ($data =~ m|JFIF|)
    {
    	$type = 'jpeg';
    	
    	# This is a kludge: I just look for the three bytes that start the header for the two embedded images
    	# but those three bytes could appear with the data stream not at a record boundary.
    	# The right way to do it is to parse the records, but this was good enough to recover my lost photos.
 
    	$dataOut =~ /(\xff\xd8....JFIF.+)(\xff\xdb\x00.+)(\xff\xdb\x00.+)/s or die "can't find JFIF bits" or die 'can\'t parse JPEG file';

    	$dataOut = $1 . $3;
    	$outfilename = $data =~ m|DCIM/100APPLE/(.*\.JPG)| ? $1 : "unknown.jpg";
    }
    else
    {
    	$type = "unknown";
    	$outfilename = "unknown.foo";
    }

    # Helpful progress report
    printf STDERR "%-60s (%s) to %-25s\n", $filename, $type, $outfilename;

    open(OUTFILE, ">$outfilename") or die "Can't open $outfilename: $!";
    binmode OUTFILE; 
    print OUTFILE $dataOut;
    close(OUTFILE);
}
