#!/usr/bin/perl
# Extract all files from a Nokia File Backup (.nfb) or
# Nokia File Content (.nfc)
#
# (c) 2005 - Niklas Ögren - no@nod.se
# Free to distribute, free to steal code and earn or more likely loose money.
#
# Syntax: nfb_extract.pl FILE.nfb
#
#  .. will extract all files to FILE/
#
# Version: 2005-06-07
# Changelog: Changed output directory to be the filename without extension
#            Corrected vcf/vcs file creation in case of ncf file.

use Encode qw(decode encode from_to decode_utf8);
use Nokia::File::NFB;
use File::Basename;
use Cwd;

my $cwd = getcwd;

my $nfb = new Nokia::File::NFB;

my $nfbfile = $ARGV[0];

print "Reading file ", $nfbfile, "...\n";

$nfb->read($nfbfile);

print "Phone model is ", $nfb->phone(), "\n";
print "Phone version is ", $nfb->version(), "\n";
print "Phone firmware is ", $nfb->firmware(), "\n";

my $destdir = $nfbfile;
$destdir =~ s/.nfb$//g;
$destdir =~ s/.nfc$//g;

mkdir "$destdir";
chdir "$destdir";

foreach my $element (@{$nfb->elements()}) {
    my $name = $element->name();
    my $filename = "$destdir$name";
    $filename =~ s/\\/\//g;

    if($element->type == 1) {

	if( $filename =~ /.*\/FILES\//) {
	    my $native;

	    if( $filename =~ /FolderIndex/) {
		my $fi = $element->data;
		if($fi =~ /2\r\n\n/) {
		    my $native = substr $fi, 5;
		    $native = decode('UCS-2LE', $native);
		    $native =~ s/\\v/\//g;
		    @fi_entries = split(/\n\n/,$native);
		}
	    } elsif( $filename =~ /InfoIndex/) {
		my $fi = $element->data;
		if($fi =~ /2\r\n\n/) {
		    my $native = substr $fi, 5;
		    $native = decode('UCS-2LE', $native);
		    $native =~ s/\\v/\//g;
		    @file_entries = split(/\n\n/,$native);
		}
	    } elsif( $filename =~ /Language/) {
		$language = decode('UCS-2LE', $element->data);
		print "Phone language is $language\n";
	    } else {
		my $fh = new FileHandle(basename("$filename"), 'w');
		die "Unable to open $filename.raw for writing"	unless (defined($fh));
		binmode $fh, ':raw';
		
		print $fh $element->data();
		
		$fh->close();
		push @f_size, $element->size();
	    }

	} elsif( $filename =~ /.*\/OMA\//) {
	    print $filename, " (Size: ", $element->size(), ")\n";

	    my $fh = new FileHandle(basename("$filename"), 'w');
	    die "Unable to open $filename for writing"	unless (defined($fh));
	    binmode $fh, ':raw';
	    
	    print $fh $element->data();

	    $fh->close();

	} else {

	    print $filename, ".csv (Size: ", $element->size(), ")\n";

	    my $fh = new FileHandle(basename("$filename.csv"), 'w');
	    die "Unable to open $filename for writing"	unless (defined($fh));
	    binmode $fh, ':raw';
	    
	    my $data = decode('UCS-2LE', $element->data());
	    my $native = pack("C*", unpack("U*", $data));
	    print $fh $native;

	    $fh->close();

	}

    } else {
	chdir $cwd;
	mkdir dirname("$filename");
	chdir dirname("$filename");
    }
}

# Create the real dirs
chdir $cwd;
chdir "$destdir";
foreach (@fi_entries) {
    ($fi_name,$fi_num,$fi_type,$fi_val) = split(/\n/);
    mkdir $fi_name
}

# Rename all the files

$i=0;
foreach (@file_entries) {
    ($fi_name,$fi_num,$fi_type,$fi_val) = split(/\n/);
    print "$destdir/$fi_name (Size: ",$f_size[$i],")\n";
    rename $i,$fi_name;
    $i++;
}

