imgtools/buildrom/tools/spitool.pm
changeset 0 044383f39525
child 590 360bd6b35136
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of the License "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 package spitool;
       
    18 
       
    19 use strict;
       
    20 use Exporter;
       
    21 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
       
    22 
       
    23 $VERSION     = 1.00;
       
    24 @ISA         = qw(Exporter);
       
    25 @EXPORT      = ();
       
    26 @EXPORT_OK   = qw(createSpi);
       
    27 
       
    28 sub binarize { #converts decimal number to 4 byte litte endian format
       
    29 	my $value = shift;
       
    30 	my $remainder;
       
    31 	my $returnValue;
       
    32 	for(my $i=0;$i<4;$i++) {
       
    33 		$remainder=$value % 256;
       
    34 		$returnValue.=chr($remainder);
       
    35 		$value = ($value-$remainder)/256;
       
    36 	}
       
    37 	return $returnValue;
       
    38 }
       
    39 
       
    40 sub convertUidFromText { #converts UID from hexadeciaml text value to decimal value, passes decimal value unchanged, returns -1 if invalid UID
       
    41 	my $value = shift;
       
    42 	if($value =~ /^0x([\da-fA-F]{1,8})$/i) {
       
    43 		return hex $1;
       
    44 	} elsif ($value =~ /^\d*$/) {
       
    45 		return $value;
       
    46 	} else {
       
    47 		return -1;
       
    48 	}
       
    49 }
       
    50 
       
    51 sub bin2hex { #converts 4 byte little endian value to 0x... hex text value
       
    52 	my $value=shift;
       
    53 	my $byte;
       
    54 	my $quotient;
       
    55 	my $remainder;
       
    56 	my $hexValue="";
       
    57 	for(my $i=0;$i<4;$i++) {
       
    58 		$byte=ord(substr($value,$i,1));
       
    59 		$remainder=$byte%16;
       
    60 		$quotient=($byte-$remainder)/16;
       
    61 		if($remainder>9) {
       
    62 			$remainder= chr($remainder+55);
       
    63 		}
       
    64 		if($quotient>9) {
       
    65 			$quotient= chr($quotient+55);
       
    66 		}		
       
    67 		$hexValue=$quotient . $remainder . $hexValue;
       
    68 	}
       
    69 	return "0x" . $hexValue;
       
    70 }
       
    71 
       
    72 sub uidcrc { #returns decimal UID checksum value for the three inputs
       
    73 	my $output = `uidcrc $_[0] $_[1] $_[2]`;
       
    74 	if($output =~ /([^ ]*)$/i) {
       
    75 		$output =$1;
       
    76 		chomp $output;
       
    77 		return hex($output);
       
    78 	}	
       
    79 }
       
    80 
       
    81 sub printZeroes { #prints as many hexadecimal zeroes to OUTPUTFILE as specified by input
       
    82 	my $numberOfZeroes=shift;
       
    83 	for(my $i=0;$i<$numberOfZeroes;$i++) {
       
    84 		print OUTPUTFILE chr(0);
       
    85 	}
       
    86 }
       
    87 
       
    88 sub bytes2dec { #calculates decimal value from inputted 4 byte little endian value 
       
    89 	my $bytes=shift;
       
    90 	my @byteArray;
       
    91 	for(my $i=0;$i<length $bytes;$i++) {
       
    92 		$byteArray[$i]=ord(substr($bytes,$i,1));
       
    93 	}
       
    94 	my $decValue;
       
    95 	for(my $i=0;$i<scalar @byteArray;$i++) {
       
    96 		$decValue+=($byteArray[$i]*(2**($i*8)));
       
    97 	}
       
    98 	return $decValue;
       
    99 }
       
   100 
       
   101 sub print_usage
       
   102 	{
       
   103 #........1.........2.........3.........4.........5.........6.........7.....
       
   104 	print <<USAGE_EOF;
       
   105 
       
   106 Usage:
       
   107   spitool.pl [options] files directories   
       
   108 
       
   109 Create an SPI file by concatenating the files and contents of directories,
       
   110 based on the options passed. 
       
   111 
       
   112 The available options are:
       
   113 
       
   114 -tSPIFileName       -- SPIFileName is the name the produced SPI file will 
       
   115                        have (i.e. ecom-0-0.spi). If not specified, the name 
       
   116                        will be ecom-0-0.spi by default
       
   117 -dTargetDir         -- TargetDir is the directory where the SPI file should
       
   118                        be created, ending with a \
       
   119 -iExisting          -- Existing is address and name of existing SPI file to
       
   120                        concatenate specified files to 
       
   121 -uid<x>=<y>         -- <x> has value 1, 2 or 3, <y> is an UID value in
       
   122                        decimal or 0x... hexadecimal
       
   123 -existinguid<x>=<y> -- <x> has value 1, 2 or 3, <y> is an UID value in 
       
   124                        decimal or 0x... hexadecimal
       
   125 -existinguidcrc=<x> -- <x> is an UID value in decimal or 0x.. hexadecimal
       
   126 -hide<ResourceFileNames> -- <ResourceFileNames> is the list of the resource files
       
   127 			    that are to be hidden in the SPI file separated by
       
   128 			    space or comma.
       
   129   
       
   130 If an existing SPI file is specified with the -i option then this file is
       
   131 used as a base and other data files are added to the end of this file,
       
   132 otherwise a new SPI file is created. In either case the produced SPI file
       
   133 is placed in the directory specified by the -d option and given the name 
       
   134 specified with the -t option.
       
   135 
       
   136 Files which are to be concatenated into the SPI file should be specified
       
   137 on the command line by either specifying the file's name (and location), or
       
   138 by including a directory name, in which case all files from that directory
       
   139 will be included.
       
   140 
       
   141 The -uid options can be used to filter files for inclusion in the SPI file.
       
   142 This option can be included multiple times, so a list of UID1 values can be
       
   143 built up, and the same for UID2 and UID3 values. Each file on the command
       
   144 line is compared with this list, and if any of its UID values match a
       
   145 relevant value in the UID lists then that file will be included in the SPI
       
   146 file. If the file does not match any values it will be excluded.
       
   147 
       
   148 The -existinguid options allow the UID values that an existing SPI file
       
   149 should have to be specified. This will allow the possibility of checking
       
   150 that the correct type of files are being concatenated together.
       
   151 
       
   152 The -hide option can be used to mark a resource file as hidden in the SPI file.
       
   153 To mark a resource file as a hidden entry in the SPI file, the resource data 
       
   154 length will be written as 0.
       
   155 
       
   156 USAGE_EOF
       
   157 	}
       
   158 
       
   159 sub createSpi 
       
   160 	{
       
   161 	my @resourceFiles=();
       
   162 	my @hideresourceFiles=();
       
   163 	my $spiFileName;
       
   164 	my $targetDirectory;
       
   165 	my $existingSpiFileName;
       
   166 	my @uid;
       
   167 	my @uidLengths = (0, 0, 0, 0);
       
   168 	my @uid1;
       
   169 	my @uid2;
       
   170 	my @uid3;
       
   171 	my @existingUid = (-1,-1,-1,-1);
       
   172 	my $uidNumber;
       
   173 	my $defaultSpiFileName = "ecom-0-0.spi";
       
   174 	my $defaultTargetDirectory = "$ENV{EPOCROOT}epoc32\\tools\\";
       
   175 	my @defaultUid = (-1,-1,-1,-1);
       
   176 	
       
   177 ##########################################################################################
       
   178 # Reading arguments phase
       
   179 ##########################################################################################
       
   180 
       
   181 	foreach my $arg (@_) {
       
   182 		if ($arg =~ /^-t(.*)/i) { # set target SPI file
       
   183 			$spiFileName = $1;
       
   184 			next;
       
   185 			}
       
   186 		if ($arg =~ /^-d(.*)/i) { # set target ouput directory
       
   187 			my $tempDirectory=$1;
       
   188 			if((-d $tempDirectory) ) {
       
   189 				$targetDirectory = $tempDirectory;
       
   190 				next;
       
   191 				}
       
   192 				else
       
   193 				{
       
   194 				 print "Output directory \'",$tempDirectory,"\' does not exist.\n";
       
   195 				 exit(1);
       
   196 				 }				
       
   197 			}
       
   198 		if ($arg =~ /^-i(.*)/i) { # existing SPI file to use as a base
       
   199 			my $tempFileName = $1;
       
   200 			if((-e $tempFileName) && (!(-d $tempFileName))) {
       
   201 				$existingSpiFileName = $tempFileName;
       
   202 				next;
       
   203 				}
       
   204 			}
       
   205 		if ($arg =~ /^-uid([1-3])\=(.*)/i) {
       
   206 			$uid[$1-1][$uidLengths[$1-1]++] = $2;
       
   207 			next;
       
   208 			}
       
   209 		if($arg=~/^-existinguidcrc\=(.*)/i) {
       
   210 			$existingUid[3]=$1;
       
   211 			next;
       
   212 			}
       
   213 		if ($arg =~ /^-existinguid([1-3])\=(.*)/i) {
       
   214 			$existingUid[$1-1]=$2;
       
   215 			next;
       
   216 			}
       
   217 		if ($arg =~ /^-hide(.*)/i) { # Collect the files to be hidden
       
   218 			my $line = $1;
       
   219 			$line =~ s/,/ /g;
       
   220 			my @files = split(' ' , $line);
       
   221 			foreach my $file (@files)
       
   222 			{
       
   223 				push @hideresourceFiles, $file;
       
   224 			}
       
   225 			next;
       
   226 			}
       
   227 		if (-d $arg) {
       
   228 			if(($arg =~ m-^.:-) && ($arg =~ m-\\$-)) {
       
   229 				unless(opendir(DIRECTORY, $arg)) { print "Exiting: $arg"; exit; }
       
   230 				while (my $file=readdir(DIRECTORY)) {
       
   231 					my $newfile = $arg.$file;
       
   232 					if(!(-d $newfile)) {
       
   233 						push @resourceFiles, $newfile;
       
   234 					}
       
   235 				}
       
   236 				close(DIRECTORY);
       
   237 				next;
       
   238 				}
       
   239 			}
       
   240 		if ((-e $arg) && (!(-d $arg))) {
       
   241 			push @resourceFiles, $arg;
       
   242 			next;
       
   243 			}
       
   244 		if ($arg eq "-h") {
       
   245 			print_usage;
       
   246 			exit(1);
       
   247 		}	
       
   248 		print "Unknown command: $arg\n";
       
   249 	}
       
   250 
       
   251 #####################################################################################
       
   252 # UID phase
       
   253 #####################################################################################
       
   254 		
       
   255 	if(!(defined $spiFileName)) { #use default file name if none passed on command line
       
   256 		$spiFileName = $defaultSpiFileName;
       
   257 	}
       
   258 	if(!(defined $targetDirectory)) { #use default target dir if none passed on command line
       
   259 		$targetDirectory = $defaultTargetDirectory;
       
   260 	}
       
   261 	for(my $i=0;$i<3;$i++) { #if default UIDs specified then added to UID match lists
       
   262 		if($defaultUid[$i]>=0) {
       
   263 			$uid[$i][$uidLengths[$i]++] = $defaultUid[$i];
       
   264 		}
       
   265 	}
       
   266 	for(my $i=0;$i<3;$i++) { #makes sure UIDs are valid UIDs
       
   267 		my @tempUidArray;
       
   268 		my $iterator=0;
       
   269 		while(defined $uid[$i][$iterator]) {
       
   270 			my $convertedUid=convertUidFromText($uid[$i][$iterator]);
       
   271 			if ($convertedUid != -1) {
       
   272 				push @tempUidArray, binarize($convertedUid);
       
   273 			} else {
       
   274 				print "Invalid UID: $uid[$i][$iterator]\n";
       
   275 			}
       
   276 			$iterator++;
       
   277 		}
       
   278 		for(my $j=0;$i<scalar @tempUidArray;$j++) {
       
   279 			$uid[$i][$j]=$tempUidArray[$j];
       
   280 		}
       
   281 		for(my $j=scalar@tempUidArray;defined $uid[$i][$j];$j++) {
       
   282 			undef $uid[$i][$j];
       
   283 		}
       
   284 	}
       
   285 #####################################################################################
       
   286 # Phase to split up resource names
       
   287 #####################################################################################
       
   288 
       
   289 	my @resourceFilePaths;
       
   290 	my @resourceFileNames;
       
   291 	my @resourceExtensions;
       
   292 	my @filestobehidden;
       
   293 
       
   294 # To mark the resource files as hidden in the SPI file by writing the data length as zero
       
   295 	foreach my $file (@hideresourceFiles)
       
   296 	{
       
   297 		my $matchfound =0;
       
   298 		my $i=0;
       
   299 		for(;$i<scalar @resourceFiles && !$matchfound;$i++)
       
   300 		{
       
   301 			if (lc($file) eq lc($resourceFiles[$i]))
       
   302 			{
       
   303 				$filestobehidden[$i] = 1;
       
   304 				$matchfound =1;
       
   305 			}
       
   306 		}
       
   307 		if (!$matchfound)
       
   308 		{
       
   309 # Those files that are to be hidden in the SPI file but not existing in the SPI
       
   310 			if (! -e $file)
       
   311 			{
       
   312 				print "Warning: Hiding non-existent file $file\n";
       
   313 			}
       
   314 			push @resourceFiles,$file;
       
   315 			$filestobehidden[$i] = 1;
       
   316 		}
       
   317 	}
       
   318 	
       
   319 	for(my $i=0;$i<scalar @resourceFiles;$i++) {
       
   320 		if($resourceFiles[$i]=~m|\\|) {
       
   321 			if($resourceFiles[$i]=~m|(.*)\\([^\\]*)$|) {
       
   322 				$resourceFilePaths[$i]=$1;
       
   323 				$resourceFileNames[$i]=$2;
       
   324 			}
       
   325 			if($resourceFileNames[$i]=~m|(.*)\.([^\.]*)|) {
       
   326 				$resourceFileNames[$i]= $1;
       
   327 				$resourceExtensions[$i]=$2;
       
   328 			}
       
   329 		} else {
       
   330 			$resourceFilePaths[$i]="";
       
   331 			if($resourceFiles[$i]=~m|(.*)\.([^\.]*)|) {
       
   332 				$resourceFileNames[$i]= $1;
       
   333 				$resourceExtensions[$i]=$2;
       
   334 			}
       
   335 		}
       
   336 	}
       
   337 	
       
   338 	my %uid2values; #hash to hold UID2 values for each type of SPI file
       
   339 	$uid2values{"ecom"} = 270556204;
       
   340 
       
   341 ##########################################################
       
   342 # Existing file stage
       
   343 ##########################################################
       
   344 
       
   345 	my @spiUid = (270556203, 0, 0); #holds spi values (including CRC value)
       
   346 	foreach my $key (keys(%uid2values)) { #searches through SPI types to match UID2 value
       
   347 		if($spiFileName =~/^$key/) {
       
   348 			$spiUid[1]=$uid2values{$key};
       
   349 		}
       
   350 	}
       
   351 	$spiUid[3] = uidcrc($spiUid[0], $spiUid[1], $spiUid[2]);
       
   352 	my $total=0; #used to keep track of position in SPI file
       
   353 	my $buffer;
       
   354 	my $spifile=File::Spec->catpath( "", $targetDirectory, $spiFileName );
       
   355  	open OUTPUTFILE, ">$spifile" or die $!;
       
   356 	binmode (OUTPUTFILE);
       
   357 	if($existingSpiFileName) {
       
   358 		open EXISTINGFILE, "$existingSpiFileName" or die $!;
       
   359 		binmode (EXISTINGFILE);
       
   360 
       
   361 		my @fileNameLengths;
       
   362 		my @fileLengths;
       
   363 		my @fileNames;
       
   364 		my @fileContents;
       
   365 
       
   366 		read(EXISTINGFILE,$buffer,4);
       
   367 		read(EXISTINGFILE,$buffer,4);
       
   368 		if(bytes2dec($buffer)!=$spiUid[1]) {
       
   369 			print "Incompatible SPI files.\n";
       
   370 		}
       
   371 		read(EXISTINGFILE,$buffer,24);
       
   372 		$total=32;
       
   373 		my $existingSpiFileSize = (stat(EXISTINGFILE))[7];
       
   374 		while($total<$existingSpiFileSize) { #loop to store information from files which are not being replaced
       
   375 			read(EXISTINGFILE,$buffer,4);
       
   376 			push @fileNameLengths, bytes2dec($buffer);
       
   377 			read(EXISTINGFILE,$buffer,4);
       
   378 			push @fileLengths, bytes2dec($buffer);
       
   379 			read(EXISTINGFILE,$buffer,$fileNameLengths[$#fileNameLengths]);
       
   380 			push @fileNames, $buffer;
       
   381 			$total=$total+8+$fileNameLengths[$#fileNameLengths]+$fileLengths[$#fileLengths];
       
   382 			my $padding = (4-(($fileNameLengths[$#fileNameLengths]+$fileLengths[$#fileLengths])%4))%4;
       
   383 			read(EXISTINGFILE,$buffer,$fileLengths[$#fileLengths]+$padding);
       
   384 			push @fileContents, $buffer;
       
   385 			$total += (4-($total%4))%4;			
       
   386 		}
       
   387 		close EXISTINGFILE;	
       
   388 		#next part prints to OUTPUTFILE the header and files which are not being replaced
       
   389 		print OUTPUTFILE binarize($spiUid[0]) . binarize($spiUid[1]) . binarize($spiUid[2]) . binarize($spiUid[3]);
       
   390 		printZeroes(16);
       
   391 		$total=32;
       
   392 		for(my $i=0; $i<scalar @fileNames; $i++) {
       
   393 			my $flag=1;
       
   394 			for(my $j=0; $j<scalar @resourceFileNames && $flag==1; $j++) {
       
   395 				if($fileNames[$i] eq $resourceFileNames[$j]) {
       
   396 					$flag=0;
       
   397 				}
       
   398 			}
       
   399 			if($flag) {
       
   400 				print OUTPUTFILE binarize($fileNameLengths[$i]) . binarize($fileLengths[$i]) . $fileNames[$i] . $fileContents[$i];
       
   401 				$total=$total+8+length($fileNames[$i])+length($fileContents[$i]);
       
   402 			}
       
   403 		}
       
   404 	} else { #prints header for target SPI file if there is no existing SPI file
       
   405 		print OUTPUTFILE binarize($spiUid[0]) . binarize($spiUid[1]) . binarize($spiUid[2]) . binarize($spiUid[3]);
       
   406 		printZeroes(16);
       
   407 		$total=32;
       
   408 	}
       
   409 
       
   410 ####################################################################
       
   411 # Appending new data files to the SPI file
       
   412 ####################################################################
       
   413 
       
   414 	my $resourceFileSize;
       
   415 	my $resourceFileSizeInBinary;
       
   416 	my $resourceFileNameSize;
       
   417 	my $resourceFileNameSizeInBinary;
       
   418 	for(my $i=0; $i<scalar @resourceExtensions;$i++) {
       
   419 # To mark the resource files as hidden in the SPI file by writing the data length as zero
       
   420 	   if ($filestobehidden[$i] == 1)
       
   421 	   {
       
   422 		$resourceFileNameSize = length($resourceFileNames[$i]);
       
   423 		$resourceFileNameSizeInBinary = binarize($resourceFileNameSize);
       
   424 		$resourceFileSize = 0;
       
   425 		$resourceFileSizeInBinary = binarize($resourceFileSize);
       
   426 		print OUTPUTFILE $resourceFileNameSizeInBinary . $resourceFileSizeInBinary . $resourceFileNames[$i];
       
   427 		$total+=$resourceFileNameSize;
       
   428 		my $padding = (4-(($resourceFileSize + $resourceFileNameSize)%4))%4;
       
   429 		printZeroes($padding);
       
   430 		$total+=$padding;
       
   431 	   }
       
   432 	   else
       
   433 	   {
       
   434 		open RESOURCEFILE, "<$resourceFiles[$i]";
       
   435 		binmode(RESOURCEFILE);
       
   436 		my @fileUid; #stores UIDs from particular data file
       
   437 		my $fileUid1;
       
   438 		my $fileUid2;
       
   439 		my $fileUid3;
       
   440 		read(RESOURCEFILE,$fileUid[0],4);
       
   441 		read(RESOURCEFILE,$fileUid[1],4);
       
   442 		read(RESOURCEFILE,$fileUid[2],4);
       
   443 		my $uidFlag=0; #changes to 1 if a UID value in data file matches a specified UID value
       
   444 		my $uidExists=1; #changes to 1 if there are specified UIDs to match to
       
   445 		for(my $j=0;$j<3 && (!$uidFlag);$j++) {
       
   446 			my $k=0;
       
   447 			while(defined $uid[$j][$k] && (!$uidFlag)) {
       
   448 				$uidExists=0;
       
   449 				if($uid[$j][$k] eq bin2hex($fileUid[$j])) {
       
   450 					$uidFlag=1;
       
   451 				}
       
   452 				$k++;
       
   453 			}
       
   454 		}	
       
   455 		if(($uidFlag) || ($uidExists)) { #if suitable UIDs writes data file to SPI file
       
   456 			$resourceFileSize = (stat(RESOURCEFILE))[7];
       
   457 			$resourceFileNameSize = length($resourceFileNames[$i]);
       
   458 			$resourceFileNameSizeInBinary = binarize($resourceFileNameSize);
       
   459 			$resourceFileSizeInBinary = binarize($resourceFileSize);
       
   460 			print OUTPUTFILE $resourceFileNameSizeInBinary . $resourceFileSizeInBinary . $resourceFileNames[$i];
       
   461 			print OUTPUTFILE "$fileUid[0]$fileUid[1]$fileUid[2]";
       
   462 			while(read(RESOURCEFILE,$buffer,1)) {
       
   463 				print OUTPUTFILE $buffer;
       
   464 			}
       
   465 			$total+=$resourceFileSize;
       
   466 			$total+=8;
       
   467 			$total+=$resourceFileNameSize;
       
   468 			my $padding = (4-(($resourceFileSize + $resourceFileNameSize)%4))%4;
       
   469 			printZeroes($padding);
       
   470 			$total+=$padding;
       
   471 		}
       
   472 	   }
       
   473 	}
       
   474 	print "Created $spiFileName\n";
       
   475 }
       
   476 
       
   477 
       
   478 1;