|
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; |