#!/usr/bin/perl

# makeFirmware.pl 
# Owen O Byrne 2007-03-02.
#
# v0.1 - Owen O Byrne - Initial Release
#   Takes a romfs file and creates an Mvix MX-760HD .pkg firmware file.
#
# v0.2 - Owen O Byrne - 2007-03-06
#   Added the -o flag.
#
# Use for whatever purpose you like. 
# Improve and post back to the group!
#
# ----------------- IMPORTANT!!!!! ---------------------
# ----- Don't blame me if this bricks your player! -----
# ------------------------------------------------------
# It may be possible to unbrick the player using TFTP. Instructions
# will be provided when they are available!

use File::Path;
use File::Copy;
use Getopt::Long;
if (@ARGV != 3) { 
	print "Usage: $0 <ROMFSFILE> -o <OUTPUT FIRMWARE FILE>\n\n";
	exit(1);
}

$outputfile = "";
GetOptions("o=s"=>\$outputfile);

# make sure the user understands what's happening
&getUserAcceptance();

$today = &isoDate();
$today =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
($year, $month, $date) = ($1, $2, $3);

# we don't know what this byte is for yet - it changes with each fw release.
$unknownbyte16 = "01";

# Setting this will set the name of the file and the header version. When you 
# select the firmware file in the GUI it will use this version number, but this 
# is not the version as seen by the player once installed. To change what the player
# sees once installed you must edit /etc/firmware_version in the ROMFS.
$releaseMajor = 1;
$releaseMinor = 1;
$releaseBuild = 18;

$romfs = $ARGV[0];
if (! -e $romfs) {
	print "ROMFS file: $romfs doesn't exist!\n\n";
	exit(1);
}
print "\nUsing ROMFS: $romfs\n";

$romfsname = "update_temp.bin";

# we need the length of the original ROMFS file
$romfs_size = -s "$romfs";

# gzip the romfs in a tmp dir.
print "Compressing ROMFS... ";
$tmpdir = "tmp.".$$;
mkdir($tmpdir) or die("Can't create tmp directory $tmpdir: $!");
copy($romfs, $tmpdir) or die("Can't copy $romfs to $tmpdir: $!");
system("mv $tmpdir/$romfs $tmpdir/$romfsname");
system("gzip $tmpdir/$romfsname");
print "Done!\n";

# get the MD5 hash of the compressed file
print "Calculating MD5 Hash of compressed ROMFS... ";
open(MD5, "md5sum -b $tmpdir/$romfsname.gz| ") or die("Can't calculate MD5 Hash: $!");
$output = <MD5>;
close(MD5);
print "Done!\n";

$romfs_compressed_md5hash = substr($output, 0, 32);

# read the compressed file into a variable.
open(FILE, "$tmpdir/$romfsname.gz") or die("Can't open compressed ROMFS file $tmpdir/$romfsname.gz: $!");
binmode(FILE);
$filedata = join("", <FILE>);
close(FILE);

# remove the tmp dir.
system("rm -rf $tmpdir");

# create the firmware
print "Packing the Firmware... ";
$firmware = "";
# magic number
$firmware .= "MVIX 1.0"; 
# zeroes
$firmware .= pack("H16", "00000000000000000000000000000000"); 
# always 0101?
$firmware .= pack("H4", "0101"); 
# date
$firmware .= pack("H8", sprintf("%02x%02x%02x%02x", $year & 255, $year>>8 & 255, $month, $date)); 
# unknown byte - doesn't seem to matter
$firmware .= pack("H4", "$unknownbyte16"."00"); 
# version
$firmware .= pack("H8", sprintf("%02x%02x%02x%02x", $releaseMajor, $releaseMinor, $releaseBuild & 255, $releaseBuild>>8 & 255)); 
# hash of romfs
$firmware .= pack("H32", $romfs_compressed_md5hash); 
# length of romfs
$firmware .= pack("H8", sprintf("%02x%02x%02x%02x", $romfs_size & 255, $romfs_size>>8 & 255, $romfs_size>>16 & 255, $romfs_size>>24 & 255)); 
# zeroes
$firmware .= pack("H120", "00"x60); 
# the compressed romfs
$firmware .= $filedata; 
print "Done!\n";

# open a file to write.

print "Writing $outputfile... ";
open(FILE, "+>$outputfile") or die("Can't open $outputfile for writing: $!");
binmode(FILE);
print FILE $firmware;
close(FILE);
print "Done!\n";

print "\n\nComplete!\n\n";
exit(0);


sub getUserAcceptance {
	print "\n\n";
	print "----------------- IMPORTANT! --------------------\n";
	print "- This script creates new firmware packages     -\n";
	print "- for your Mvix MX-760HD. Use of these packages -\n";
	print "- may render your player unusable, and will     -\n";
	print "- probably invalidate your warranty! This will  -\n";
	print "- be completely your own fault and you will not -\n";
	print "- blame anyone else for this right?!            -\n";
	print "-------------------------------------------------\n";
	print "\n";
	print "Is this ok with you? (y/n)\n";
	$reply = <STDIN>;

	if ($reply !~ /^y$/i) { exit(1); }
}

sub isoDate {
	my %months = qw(Jan 01 Feb 02 Mar 03 Apr 04 May 05 Jun 06 Jul 07 Aug 08 Sep 09 Oct 10 Nov 11 Dec 12);
	my $now = shift || scalar localtime;
	my ($day_name, $month, $day, $time, $year) = split(/\s+/, $now);
	my ($hour, $min, $sec) = split(/:/, $time);
	my $strDate = sprintf("%04d%02d%02d%02d%02d%02d", $year, $months{$month}, $day, $hour, $min, $sec);
	return $strDate;
}
