imgtools/buildrom/tools/spitool.pm
changeset 0 044383f39525
child 590 360bd6b35136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imgtools/buildrom/tools/spitool.pm	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,478 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+#
+
+package spitool;
+
+use strict;
+use Exporter;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+$VERSION     = 1.00;
+@ISA         = qw(Exporter);
+@EXPORT      = ();
+@EXPORT_OK   = qw(createSpi);
+
+sub binarize { #converts decimal number to 4 byte litte endian format
+	my $value = shift;
+	my $remainder;
+	my $returnValue;
+	for(my $i=0;$i<4;$i++) {
+		$remainder=$value % 256;
+		$returnValue.=chr($remainder);
+		$value = ($value-$remainder)/256;
+	}
+	return $returnValue;
+}
+
+sub convertUidFromText { #converts UID from hexadeciaml text value to decimal value, passes decimal value unchanged, returns -1 if invalid UID
+	my $value = shift;
+	if($value =~ /^0x([\da-fA-F]{1,8})$/i) {
+		return hex $1;
+	} elsif ($value =~ /^\d*$/) {
+		return $value;
+	} else {
+		return -1;
+	}
+}
+
+sub bin2hex { #converts 4 byte little endian value to 0x... hex text value
+	my $value=shift;
+	my $byte;
+	my $quotient;
+	my $remainder;
+	my $hexValue="";
+	for(my $i=0;$i<4;$i++) {
+		$byte=ord(substr($value,$i,1));
+		$remainder=$byte%16;
+		$quotient=($byte-$remainder)/16;
+		if($remainder>9) {
+			$remainder= chr($remainder+55);
+		}
+		if($quotient>9) {
+			$quotient= chr($quotient+55);
+		}		
+		$hexValue=$quotient . $remainder . $hexValue;
+	}
+	return "0x" . $hexValue;
+}
+
+sub uidcrc { #returns decimal UID checksum value for the three inputs
+	my $output = `uidcrc $_[0] $_[1] $_[2]`;
+	if($output =~ /([^ ]*)$/i) {
+		$output =$1;
+		chomp $output;
+		return hex($output);
+	}	
+}
+
+sub printZeroes { #prints as many hexadecimal zeroes to OUTPUTFILE as specified by input
+	my $numberOfZeroes=shift;
+	for(my $i=0;$i<$numberOfZeroes;$i++) {
+		print OUTPUTFILE chr(0);
+	}
+}
+
+sub bytes2dec { #calculates decimal value from inputted 4 byte little endian value 
+	my $bytes=shift;
+	my @byteArray;
+	for(my $i=0;$i<length $bytes;$i++) {
+		$byteArray[$i]=ord(substr($bytes,$i,1));
+	}
+	my $decValue;
+	for(my $i=0;$i<scalar @byteArray;$i++) {
+		$decValue+=($byteArray[$i]*(2**($i*8)));
+	}
+	return $decValue;
+}
+
+sub print_usage
+	{
+#........1.........2.........3.........4.........5.........6.........7.....
+	print <<USAGE_EOF;
+
+Usage:
+  spitool.pl [options] files directories   
+
+Create an SPI file by concatenating the files and contents of directories,
+based on the options passed. 
+
+The available options are:
+
+-tSPIFileName       -- SPIFileName is the name the produced SPI file will 
+                       have (i.e. ecom-0-0.spi). If not specified, the name 
+                       will be ecom-0-0.spi by default
+-dTargetDir         -- TargetDir is the directory where the SPI file should
+                       be created, ending with a \
+-iExisting          -- Existing is address and name of existing SPI file to
+                       concatenate specified files to 
+-uid<x>=<y>         -- <x> has value 1, 2 or 3, <y> is an UID value in
+                       decimal or 0x... hexadecimal
+-existinguid<x>=<y> -- <x> has value 1, 2 or 3, <y> is an UID value in 
+                       decimal or 0x... hexadecimal
+-existinguidcrc=<x> -- <x> is an UID value in decimal or 0x.. hexadecimal
+-hide<ResourceFileNames> -- <ResourceFileNames> is the list of the resource files
+			    that are to be hidden in the SPI file separated by
+			    space or comma.
+  
+If an existing SPI file is specified with the -i option then this file is
+used as a base and other data files are added to the end of this file,
+otherwise a new SPI file is created. In either case the produced SPI file
+is placed in the directory specified by the -d option and given the name 
+specified with the -t option.
+
+Files which are to be concatenated into the SPI file should be specified
+on the command line by either specifying the file's name (and location), or
+by including a directory name, in which case all files from that directory
+will be included.
+
+The -uid options can be used to filter files for inclusion in the SPI file.
+This option can be included multiple times, so a list of UID1 values can be
+built up, and the same for UID2 and UID3 values. Each file on the command
+line is compared with this list, and if any of its UID values match a
+relevant value in the UID lists then that file will be included in the SPI
+file. If the file does not match any values it will be excluded.
+
+The -existinguid options allow the UID values that an existing SPI file
+should have to be specified. This will allow the possibility of checking
+that the correct type of files are being concatenated together.
+
+The -hide option can be used to mark a resource file as hidden in the SPI file.
+To mark a resource file as a hidden entry in the SPI file, the resource data 
+length will be written as 0.
+
+USAGE_EOF
+	}
+
+sub createSpi 
+	{
+	my @resourceFiles=();
+	my @hideresourceFiles=();
+	my $spiFileName;
+	my $targetDirectory;
+	my $existingSpiFileName;
+	my @uid;
+	my @uidLengths = (0, 0, 0, 0);
+	my @uid1;
+	my @uid2;
+	my @uid3;
+	my @existingUid = (-1,-1,-1,-1);
+	my $uidNumber;
+	my $defaultSpiFileName = "ecom-0-0.spi";
+	my $defaultTargetDirectory = "$ENV{EPOCROOT}epoc32\\tools\\";
+	my @defaultUid = (-1,-1,-1,-1);
+	
+##########################################################################################
+# Reading arguments phase
+##########################################################################################
+
+	foreach my $arg (@_) {
+		if ($arg =~ /^-t(.*)/i) { # set target SPI file
+			$spiFileName = $1;
+			next;
+			}
+		if ($arg =~ /^-d(.*)/i) { # set target ouput directory
+			my $tempDirectory=$1;
+			if((-d $tempDirectory) ) {
+				$targetDirectory = $tempDirectory;
+				next;
+				}
+				else
+				{
+				 print "Output directory \'",$tempDirectory,"\' does not exist.\n";
+				 exit(1);
+				 }				
+			}
+		if ($arg =~ /^-i(.*)/i) { # existing SPI file to use as a base
+			my $tempFileName = $1;
+			if((-e $tempFileName) && (!(-d $tempFileName))) {
+				$existingSpiFileName = $tempFileName;
+				next;
+				}
+			}
+		if ($arg =~ /^-uid([1-3])\=(.*)/i) {
+			$uid[$1-1][$uidLengths[$1-1]++] = $2;
+			next;
+			}
+		if($arg=~/^-existinguidcrc\=(.*)/i) {
+			$existingUid[3]=$1;
+			next;
+			}
+		if ($arg =~ /^-existinguid([1-3])\=(.*)/i) {
+			$existingUid[$1-1]=$2;
+			next;
+			}
+		if ($arg =~ /^-hide(.*)/i) { # Collect the files to be hidden
+			my $line = $1;
+			$line =~ s/,/ /g;
+			my @files = split(' ' , $line);
+			foreach my $file (@files)
+			{
+				push @hideresourceFiles, $file;
+			}
+			next;
+			}
+		if (-d $arg) {
+			if(($arg =~ m-^.:-) && ($arg =~ m-\\$-)) {
+				unless(opendir(DIRECTORY, $arg)) { print "Exiting: $arg"; exit; }
+				while (my $file=readdir(DIRECTORY)) {
+					my $newfile = $arg.$file;
+					if(!(-d $newfile)) {
+						push @resourceFiles, $newfile;
+					}
+				}
+				close(DIRECTORY);
+				next;
+				}
+			}
+		if ((-e $arg) && (!(-d $arg))) {
+			push @resourceFiles, $arg;
+			next;
+			}
+		if ($arg eq "-h") {
+			print_usage;
+			exit(1);
+		}	
+		print "Unknown command: $arg\n";
+	}
+
+#####################################################################################
+# UID phase
+#####################################################################################
+		
+	if(!(defined $spiFileName)) { #use default file name if none passed on command line
+		$spiFileName = $defaultSpiFileName;
+	}
+	if(!(defined $targetDirectory)) { #use default target dir if none passed on command line
+		$targetDirectory = $defaultTargetDirectory;
+	}
+	for(my $i=0;$i<3;$i++) { #if default UIDs specified then added to UID match lists
+		if($defaultUid[$i]>=0) {
+			$uid[$i][$uidLengths[$i]++] = $defaultUid[$i];
+		}
+	}
+	for(my $i=0;$i<3;$i++) { #makes sure UIDs are valid UIDs
+		my @tempUidArray;
+		my $iterator=0;
+		while(defined $uid[$i][$iterator]) {
+			my $convertedUid=convertUidFromText($uid[$i][$iterator]);
+			if ($convertedUid != -1) {
+				push @tempUidArray, binarize($convertedUid);
+			} else {
+				print "Invalid UID: $uid[$i][$iterator]\n";
+			}
+			$iterator++;
+		}
+		for(my $j=0;$i<scalar @tempUidArray;$j++) {
+			$uid[$i][$j]=$tempUidArray[$j];
+		}
+		for(my $j=scalar@tempUidArray;defined $uid[$i][$j];$j++) {
+			undef $uid[$i][$j];
+		}
+	}
+#####################################################################################
+# Phase to split up resource names
+#####################################################################################
+
+	my @resourceFilePaths;
+	my @resourceFileNames;
+	my @resourceExtensions;
+	my @filestobehidden;
+
+# To mark the resource files as hidden in the SPI file by writing the data length as zero
+	foreach my $file (@hideresourceFiles)
+	{
+		my $matchfound =0;
+		my $i=0;
+		for(;$i<scalar @resourceFiles && !$matchfound;$i++)
+		{
+			if (lc($file) eq lc($resourceFiles[$i]))
+			{
+				$filestobehidden[$i] = 1;
+				$matchfound =1;
+			}
+		}
+		if (!$matchfound)
+		{
+# Those files that are to be hidden in the SPI file but not existing in the SPI
+			if (! -e $file)
+			{
+				print "Warning: Hiding non-existent file $file\n";
+			}
+			push @resourceFiles,$file;
+			$filestobehidden[$i] = 1;
+		}
+	}
+	
+	for(my $i=0;$i<scalar @resourceFiles;$i++) {
+		if($resourceFiles[$i]=~m|\\|) {
+			if($resourceFiles[$i]=~m|(.*)\\([^\\]*)$|) {
+				$resourceFilePaths[$i]=$1;
+				$resourceFileNames[$i]=$2;
+			}
+			if($resourceFileNames[$i]=~m|(.*)\.([^\.]*)|) {
+				$resourceFileNames[$i]= $1;
+				$resourceExtensions[$i]=$2;
+			}
+		} else {
+			$resourceFilePaths[$i]="";
+			if($resourceFiles[$i]=~m|(.*)\.([^\.]*)|) {
+				$resourceFileNames[$i]= $1;
+				$resourceExtensions[$i]=$2;
+			}
+		}
+	}
+	
+	my %uid2values; #hash to hold UID2 values for each type of SPI file
+	$uid2values{"ecom"} = 270556204;
+
+##########################################################
+# Existing file stage
+##########################################################
+
+	my @spiUid = (270556203, 0, 0); #holds spi values (including CRC value)
+	foreach my $key (keys(%uid2values)) { #searches through SPI types to match UID2 value
+		if($spiFileName =~/^$key/) {
+			$spiUid[1]=$uid2values{$key};
+		}
+	}
+	$spiUid[3] = uidcrc($spiUid[0], $spiUid[1], $spiUid[2]);
+	my $total=0; #used to keep track of position in SPI file
+	my $buffer;
+	my $spifile=File::Spec->catpath( "", $targetDirectory, $spiFileName );
+ 	open OUTPUTFILE, ">$spifile" or die $!;
+	binmode (OUTPUTFILE);
+	if($existingSpiFileName) {
+		open EXISTINGFILE, "$existingSpiFileName" or die $!;
+		binmode (EXISTINGFILE);
+
+		my @fileNameLengths;
+		my @fileLengths;
+		my @fileNames;
+		my @fileContents;
+
+		read(EXISTINGFILE,$buffer,4);
+		read(EXISTINGFILE,$buffer,4);
+		if(bytes2dec($buffer)!=$spiUid[1]) {
+			print "Incompatible SPI files.\n";
+		}
+		read(EXISTINGFILE,$buffer,24);
+		$total=32;
+		my $existingSpiFileSize = (stat(EXISTINGFILE))[7];
+		while($total<$existingSpiFileSize) { #loop to store information from files which are not being replaced
+			read(EXISTINGFILE,$buffer,4);
+			push @fileNameLengths, bytes2dec($buffer);
+			read(EXISTINGFILE,$buffer,4);
+			push @fileLengths, bytes2dec($buffer);
+			read(EXISTINGFILE,$buffer,$fileNameLengths[$#fileNameLengths]);
+			push @fileNames, $buffer;
+			$total=$total+8+$fileNameLengths[$#fileNameLengths]+$fileLengths[$#fileLengths];
+			my $padding = (4-(($fileNameLengths[$#fileNameLengths]+$fileLengths[$#fileLengths])%4))%4;
+			read(EXISTINGFILE,$buffer,$fileLengths[$#fileLengths]+$padding);
+			push @fileContents, $buffer;
+			$total += (4-($total%4))%4;			
+		}
+		close EXISTINGFILE;	
+		#next part prints to OUTPUTFILE the header and files which are not being replaced
+		print OUTPUTFILE binarize($spiUid[0]) . binarize($spiUid[1]) . binarize($spiUid[2]) . binarize($spiUid[3]);
+		printZeroes(16);
+		$total=32;
+		for(my $i=0; $i<scalar @fileNames; $i++) {
+			my $flag=1;
+			for(my $j=0; $j<scalar @resourceFileNames && $flag==1; $j++) {
+				if($fileNames[$i] eq $resourceFileNames[$j]) {
+					$flag=0;
+				}
+			}
+			if($flag) {
+				print OUTPUTFILE binarize($fileNameLengths[$i]) . binarize($fileLengths[$i]) . $fileNames[$i] . $fileContents[$i];
+				$total=$total+8+length($fileNames[$i])+length($fileContents[$i]);
+			}
+		}
+	} else { #prints header for target SPI file if there is no existing SPI file
+		print OUTPUTFILE binarize($spiUid[0]) . binarize($spiUid[1]) . binarize($spiUid[2]) . binarize($spiUid[3]);
+		printZeroes(16);
+		$total=32;
+	}
+
+####################################################################
+# Appending new data files to the SPI file
+####################################################################
+
+	my $resourceFileSize;
+	my $resourceFileSizeInBinary;
+	my $resourceFileNameSize;
+	my $resourceFileNameSizeInBinary;
+	for(my $i=0; $i<scalar @resourceExtensions;$i++) {
+# To mark the resource files as hidden in the SPI file by writing the data length as zero
+	   if ($filestobehidden[$i] == 1)
+	   {
+		$resourceFileNameSize = length($resourceFileNames[$i]);
+		$resourceFileNameSizeInBinary = binarize($resourceFileNameSize);
+		$resourceFileSize = 0;
+		$resourceFileSizeInBinary = binarize($resourceFileSize);
+		print OUTPUTFILE $resourceFileNameSizeInBinary . $resourceFileSizeInBinary . $resourceFileNames[$i];
+		$total+=$resourceFileNameSize;
+		my $padding = (4-(($resourceFileSize + $resourceFileNameSize)%4))%4;
+		printZeroes($padding);
+		$total+=$padding;
+	   }
+	   else
+	   {
+		open RESOURCEFILE, "<$resourceFiles[$i]";
+		binmode(RESOURCEFILE);
+		my @fileUid; #stores UIDs from particular data file
+		my $fileUid1;
+		my $fileUid2;
+		my $fileUid3;
+		read(RESOURCEFILE,$fileUid[0],4);
+		read(RESOURCEFILE,$fileUid[1],4);
+		read(RESOURCEFILE,$fileUid[2],4);
+		my $uidFlag=0; #changes to 1 if a UID value in data file matches a specified UID value
+		my $uidExists=1; #changes to 1 if there are specified UIDs to match to
+		for(my $j=0;$j<3 && (!$uidFlag);$j++) {
+			my $k=0;
+			while(defined $uid[$j][$k] && (!$uidFlag)) {
+				$uidExists=0;
+				if($uid[$j][$k] eq bin2hex($fileUid[$j])) {
+					$uidFlag=1;
+				}
+				$k++;
+			}
+		}	
+		if(($uidFlag) || ($uidExists)) { #if suitable UIDs writes data file to SPI file
+			$resourceFileSize = (stat(RESOURCEFILE))[7];
+			$resourceFileNameSize = length($resourceFileNames[$i]);
+			$resourceFileNameSizeInBinary = binarize($resourceFileNameSize);
+			$resourceFileSizeInBinary = binarize($resourceFileSize);
+			print OUTPUTFILE $resourceFileNameSizeInBinary . $resourceFileSizeInBinary . $resourceFileNames[$i];
+			print OUTPUTFILE "$fileUid[0]$fileUid[1]$fileUid[2]";
+			while(read(RESOURCEFILE,$buffer,1)) {
+				print OUTPUTFILE $buffer;
+			}
+			$total+=$resourceFileSize;
+			$total+=8;
+			$total+=$resourceFileNameSize;
+			my $padding = (4-(($resourceFileSize + $resourceFileNameSize)%4))%4;
+			printZeroes($padding);
+			$total+=$padding;
+		}
+	   }
+	}
+	print "Created $spiFileName\n";
+}
+
+
+1;