#
# Copyright (c) 2006-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:
# This package contains fuctions specific to data drive image generation
#
package datadriveimage;
require Exporter;
@ISA=qw(Exporter);
@EXPORT=qw(
createDirectory
deleteDirectory
checkInArray
setPath
locateStubsisfiles
copyFilesToFolders
checkForSisFile
copyNonSisFiles
invokeInterpretsis
invokeReadImage
compareArrays
dumpDatadriveObydata
TraverseDir
writeDataToFile
generate_datadriveheader
checkForWhiteSpace
reportError
);
use strict;
use File::Path; # Module to provide functions to remove or create directories in a convenient way.
use File::Copy; # Module to provide functions to copy file(s) from source to destination.
use Pathutl;
use Cwd; # Module to provide functions for determining the pathname of the current working directory.
# This fuction is used primiarly to check for whitespace in the location for "zdrive" / "datadrive" folder creation,
# specified by the user, if yes then it returns one, else zero
sub checkForWhiteSpace
{
my ($dirLoc,$dirName) = @_;
if( $dirLoc =~ m/ / )
{
print "* Warning: $dirLoc contains whitespace, hence $dirName will be created in default location \n";
return 1;
}
else
{
return 0;
}
}
# This function reports the appropriate meassage supplied to it
# and does a exit if and only if keepgoing option is disabled.
sub reportError
{
my( $message,$keepgoingOpt ) = @_;
# print the specified meassage.
print STDERR "$message \n";
# bail out, if keepgoing option is not set.
exit(1) if (!$keepgoingOpt);
}
# generate header for final datadrive oby file.
sub generate_datadriveheader
{
my ($idx,$datadriveimage) = @_;
my $header;
$header = "dataimagename=$$datadriveimage[$idx]{name}.img\n";
$header .= "dataimagefilesystem=$$datadriveimage[$idx]{fstype}\n";
# check whether the size of the image has been mentioned
if(defined($$datadriveimage[$idx]{size}))
{
$header .= "dataimagesize=$$datadriveimage[$idx]{size}\n\n";
}
return $header;
}
# Create the specified directory by making use of mkpath function
# from File::Path module.
sub createDirectory
{
my($dir) = @_;
if( !-d $dir )
{
mkpath($dir);
if (! -e $dir)
{
print ("ERROR: Couldn't create $dir\n");
}
}
}
# check if the given file is a reg file or ctl file or a txt file
# if it is any of these files then return true else false.
# This check is need since these three files or not valid not valid e32 file
# and hence needs to be placed as an data file inside the image.
sub checkRegCtlFiles
{
my ($fileName) = @_;
# check whether the file has "reg","ctl" or "txt" extension.
if( $fileName =~/\.(reg|ctl|txt)$/i )
{
return 1;
}
else
{
return 0;
}
}
# delete the given directory by making use of rmtree function
# from File::Path module.
sub deleteDirectory
{
my($dir,$verboseOpt) = @_;
# check whether the directory exists.
if( -d $dir )
{
print("found $dir directory \n") if($verboseOpt);
if(rmtree($dir))
{
print("$dir directory deleted \n") if($verboseOpt);
return 0;
}
else
{
print("$dir directory could'nt be deleted \n") if($verboseOpt);
return 1;
}
}
}
# check for processed data drive image index.
# if there is a match return one else return zero.
# this check is done in order to ensure data drive image index is not repeated.
sub checkInArray
{
my($array, $value) = @_;
foreach my $aLine(@$array)
{
if( $aLine eq $value )
{
return 0;
}
}
return 1;
}
# set the path for the given directory.
sub setPath
{
my($dirName) = @_;
# get the working directory.
my $curWorkingDir = getcwd;
# substitute slash with double backward slash.
$curWorkingDir =~ s/\//\\/g;
#if $curWorkingDir already has trailing '\', don't include it again
if( $curWorkingDir =~ /\\$/)
{
return $curWorkingDir.$dirName;
}
else
{
return $curWorkingDir."\\".$dirName;
}
}
# create directory and copy respective file on to that directory.
# is there is a problem while copying files from source to destination
# then bail out if and only if keep going option is disabled.
sub copyFilesToFolders
{
my ($source,$dest,$dir,$verboseOpt) = @_;
$source =~ s/\"//g; # remove double quotes from the string.
my $destFileName = ""; # name of the destination file.
$dest =~ s/\"//g; # remove double quotes from the string.
my $destDirectory = $dest;
# strip the last substring to get destination file
if ($dest=~/.*\\(\S+)/)
{
$destFileName = $1;
}
else
{
$destFileName = $dest;
}
#get the destination directory along with full path
#when "[" and "]" appear in the file name we need add "\" before "[" or "]"
#like this: [filename].exe translate to \[filename\].exe
if($destFileName =~ /\[|\]/)
{
my $tempFileName = $destFileName;
$tempFileName =~ s/(\[|\])/\\$1/g;
$destDirectory =~ s/$tempFileName//;
}
else
{
$destDirectory =~ s/$destFileName//;
}
my $destfile = $dir."\\".$dest;
my $createdir = $dir."\\".$destDirectory ;
# create the specified directory.
&createDirectory($createdir);
if (!copy($source,$destfile))
{
warn "warning : $source file could not found \n";
return 0;
}
else
{
print "$source copied to $destfile\n" if($verboseOpt);
return $destfile;
}
}
# Make a check for sisfile keyword by reading the specified iby/oby file,
# if sisfile keyword is found then push the respective image on to the respective array
# and return true.
sub checkForSisFile
{
my($obyfile,$sisFileArray,$sisFilePrestent) = @_;
# open the oby file in read only mode.
open (DATA, "< $obyfile") or die("* Can't open $obyfile\n");
while (my $line =<DATA>)
{
if($line =~ /^\s*sisfile\s*=\s*(\S+)/i )
{
# found a sis file.
$$sisFilePrestent = 1;
# push sis file on to stack.
push(@$sisFileArray,$1);
next;
}
}
close(DATA);
return $$sisFilePrestent;
}
# Make a check for zdriveimagename keyword by reading the specified iby/oby file,
# if zdriveimagename keyword is found then push the respective image on to the respective array
# and return true.
sub checkForZDriveImageKeyword
{
#$ZDriveImageFilePresent
my($obyfile,$ZDriveImageKeywordArray,$ImageFilePresent) = @_;
# open the oby file in read only mode.
open (DATA, "< $obyfile") or die("* Can't open $obyfile\n");
while (my $line =<DATA>)
{
if($line =~ /^\s*zdriveimagename\s*=\s*(\S+)/i )
{
# found a Z Drive Image file.
$$ImageFilePresent = 1;
# push sis file on to stack.
push(@$ZDriveImageKeywordArray,$1);
next;
}
}
close(DATA);
return $$ImageFilePresent;
}
# copy all non-sis file(s) on to prototype data drive folder
# which are mentioned under input data drive iby/oby file.
sub copyNonSisFiles
{
my($dir,$obyfile,$nonsisFileArray,$renameArray,$aliasArray,$hideArray,$verboseOpt,$keepgoingOpt) = @_;
open (OBEY ,$obyfile) or die($obyfile."\n");
while(my $line =<OBEY>)
{
if( $line =~ /^(file|data)\s*=\s*(\S+)\s+(\S+)/i )
{
my $keyWord=$1;
my $source=$2;
my $dest=$3;
if( $source !~ /(\S+):(\S+)/ )
{
$source = Path_Drive().$2;
}
my $var = ©FilesToFolders( $source,$dest,$dir,$verboseOpt);
if($var)
{
$var = $keyWord."=".$var;
$line =~ s/^(\S+)=(\S+)/$var/;
push(@$nonsisFileArray,$line);
}
else
{
exit(1)if(!$keepgoingOpt);
}
}
elsif($line =~ /^rename\s+(\S+)\s+(\S+)/i)
{
my $oldFile = $dir.$1; # existing-file
my $newFile = $dir.$2; # destination-file
print"found rename keyword\nrenaming $oldFile to $newFile\n" if ($verboseOpt);
if ( rename($oldFile, $newFile) )
{
# push the line on to the stack.
push(@$renameArray,$1."\t".$2."\n");
}
else
{
&datadriveimage::reportError("* Warning : can't rename $oldFile to $newFile: $!",$keepgoingOpt);
}
}
elsif($line =~ /^alias\s+(\S+)\s+(\S+)/i)
{
my $exFile = $dir.$1; # existing-file
my $destFile = $dir.$2; # destination-file
print"found alias keyword\n" if ($verboseOpt);
if(!copy($exFile,$destFile))
{
&datadriveimage::reportError("* warning : couldnt create alias of $1 to $2 ",$keepgoingOpt);
}
else
{
# push the line on to the stack.
push(@$aliasArray,$1."\t".$2."\n");
}
}
elsif($line =~ /^hide\s+(\S+)/i)
{
print"found hide keyword\n" if ($verboseOpt);
print "$1 is marked as hidden, hence will not be part of the image\n" if($verboseOpt);
if( unlink($dir.$1) )
{
# push the line on to the stack.
push(@$hideArray,$1);
}
else
{
&datadriveimage::reportError("* Warning : Can't delete $1: $! ",$keepgoingOpt);
}
}
}
close(OBEY);
}
# invoke the INTERPRETSIS tool with appropriate parameters.
sub invokeInterpretsis
{
my($sisFileArray,$dataDrivePath,$verboseOpt,$zDrivePath,$parafile,$keepgoingOpt,$interpretsisOptList) = @_;
my $sisfile = "";
# default system drive letter is specified since interpretsis doesnt allow overloading of options unless default
# options are specified.
my $basicOption = "-d C: "; # default system drive letter
my $command = "interpretsis ";
my $vOption = "-w info" if ($verboseOpt);
# do a check if the path has a white space.
if( $dataDrivePath =~ m/ /)
{
$dataDrivePath = '"'.$dataDrivePath.'"';
}
# find out size of the array
my $sisarraysize = scalar(@$sisFileArray);
for( my $i=0; $i<$sisarraysize; $i++ )
{
if($sisfile ne "")
{
$sisfile = pop(@$sisFileArray).",".$sisfile;
}
else
{
$sisfile = pop(@$sisFileArray);
}
}
# check whether the directory exists or not
if( -d $zDrivePath )
{
# do a check if the path has a white space.
if( $zDrivePath =~ m/ /)
{
$zDrivePath = '"'.$zDrivePath.'"';
}
$basicOption .= "-z $zDrivePath ";
}
$basicOption .= "-c $dataDrivePath -s $sisfile $vOption";
# if parameter file is specified then invoke the INTERPRETSIS
# with the specified parameter file with "-p" option.
if( defined($parafile) )
{
# do a check if the path has a white space.
if( $parafile =~ m/ /)
{
$parafile = '"'.$parafile.'"';
}
$command .= "-p $parafile ";
}
# else invoke the INTERPRETSIS with default parameter file with "-p" option.
else
{
# Truncate and open the parameter file for writing..
open( OPTDATA, "> parameterfile.txt" ) or die "can't open parameterfile.txt";
print OPTDATA $basicOption."\n";
close( OPTDATA );
$command .= "-p parameterfile.txt ";
}
if( $interpretsisOptList )
{
# find out size of the array
my $arraysize = scalar( @$interpretsisOptList );
for( my $i = 0; $i < $arraysize; $i++ )
{
$command .= $$interpretsisOptList[$i]." ";
}
}
print "* Executing $command\n" if ( $verboseOpt );
system ( $command );
if ($? != 0)
{
&datadriveimage::reportError("* ERROR: INTERPRETSIS failed",$keepgoingOpt);
}
}
# invoke the READIMAGE tool with appropriate parameters.
sub invokeReadImage
{
my($imageName,$loc,$verboseOpt,$logFile,$keepgoingOpt) = @_;
my $command = "readimage ";
# check if log file has been supplied.
if(defined($logFile))
{
if( $logFile =~ m/ /)
{
$logFile = '"'.$logFile.'"';
}
$command .= "-l $logFile ";
}
# do a check if the path has a white space.
if( $loc =~ m/ /)
{
$loc = '"'.$loc.'"';
}
$command .= "-z ".$loc." ".$imageName;
print "* Executing $command\n" if ($verboseOpt);
system ($command);
if ($? != 0)
{
&datadriveimage::reportError("* ERROR: READIMAGE failed to read the image",$keepgoingOpt);
return 0;
}
return 1;
}
# Each line from the OBY file is read and if any of the line contains "rename"/ "alias" keyword
# then that corresponding line source and line destination is obtained and is passed to this function as one of the parameters.
# This fuction compares given array with non-sis file(s) array, when an given line destination matches with the destination of an
# element in the rename array/alias array(array holding list of file(s) that are renamed / made alias) then,
# that respective element is removed from the rename array and a further check is made to see whether the given
# line source matches with the destination of an element in the rename array/alias array.If a match is found then
# a keyword check is done,if the keyword is "rename" then corresponding element's source and destination file is replaced
# with given line destination file and if the keyword is "alias" then a new element will be added to non sis file array
# with line destination file as the source and destination file.
sub compareArrays
{
my ( $firstarray,$nonsisArray,$linesource,$linedest,$linekeyword ) = @_;
# count of array element(s).
my $firstArrayCount = 0;
# source file.
my $linesourceFile;
# destination file.
my $linedestFile;
# get source file.
# strip first occurrence of back slash
$linesource =~ s/\\//;
# get source file.
if ($linesource =~ /.*\\(\S+)/ )
{
$linesourceFile = $1;
}
# get destination file.
if ($linedest =~ /.*\\(\S+)/ )
{
$linedestFile = $1;
}
# iterate trough all
foreach my $firstarrayEntry (@$firstarray)
{
if( $firstarrayEntry =~ /(\S+)\s+(\S+)/ )
{
my $firstarrayEntrydest = $2;
if( $linedest eq $firstarrayEntrydest )
{
# remove the specified element from the array.
splice(@$firstarray,$firstArrayCount,1);
# initialize the nonsisFileListCount to zero.
my $nonsisFileListCount = 0;
foreach my $nonsisEntry ( @$nonsisArray )
{
if( $nonsisEntry =~ /^(\S+)=(\S+)\s+(\S+)/ )
{
my $nonsisEntryDest = $3;
# remove double quotes.
$nonsisEntryDest =~ s/\"//g;
my $nonsisEntryDestFile;
if ($nonsisEntryDest =~ /.*\\(\S+)/ )
{
$nonsisEntryDestFile = $1;
}
if( $nonsisEntryDest eq $linesource )
{
if($linekeyword eq "rename")
{
# remove the specified element from the array.
splice(@$nonsisArray,$nonsisFileListCount,1);
$nonsisEntry =~ s/$nonsisEntryDestFile/$linedestFile/g;
push(@$nonsisArray,$nonsisEntry);
}
elsif($linekeyword eq "alias")
{
my $newLine = $nonsisEntry;
$newLine =~ s/$nonsisEntryDestFile/$linedestFile/g;
push(@$nonsisArray,$newLine);
}
}
}
$nonsisFileListCount++;
}#end of loop foreach my $newLine ( @nonsisArray )
}
$firstArrayCount++;
}#end of loop foreach my $newLine ( @firstarray)
}
}
# Traverse the entire directory and log the folder contents on to a file.
sub dumpDatadriveObydata
{
#assign a temporary name and extension to the new oby file.
my $newobyfile = "temp.$$";
my ($datadir,$oldobyfile,$size,$nonsisFileArray,$renameArray,$aliasArray,
$hideArray,$sisobyArray,$datadriveArray,$keepgoingOpt,$verboseOpt) = @_;
# get the working directory.
my $curWorkingDir = getcwd;
# traverse the updated data drive directory structure.
&TraverseDir($datadir,"",$sisobyArray,$datadir);
# change the directrory to the Working directory.
chdir($curWorkingDir);
# copy non-sis file(s) on to prototype data drive folder.
copyNonSisFiles($datadir,$oldobyfile,$nonsisFileArray,$renameArray,$aliasArray,$hideArray,$verboseOpt,$keepgoingOpt);
#open the oby file in read-only mode.
open (OLDDATA, "< $oldobyfile") or die("* Can't open $oldobyfile\n");
# Truncate and open the new oby file for writing..
open(NEWDATA, "> $newobyfile") or die "can't open $newobyfile";
while (my $line =<OLDDATA>)
{
if( $line =~ /^hide\s+(\S+)/i)
{
my $lineToSearch = $1;
my $hideListCount = 0;
foreach my $newLine ( @$hideArray )
{
if( $newLine eq $lineToSearch )
{
splice(@$hideArray,$hideListCount,1);
my $nonsisFileListCount = 0;
foreach my $newLine ( @$nonsisFileArray )
{
if( $newLine =~ /^(\S+)=(\S+)\s+(\S+)/ )
{
my $newLineKeyword = $1;
my $newLinesource = $2;
my $newLinedest = $3;
$newLinedest =~ s/\"//g;
$newLinedest = "\\".$newLinedest;
if( $newLinedest eq $lineToSearch )
{
# remove the specified element from the array.
splice(@$nonsisFileArray,$nonsisFileListCount,1);
}
}
# increment the non sis file list count.
$nonsisFileListCount++;
}
}
# increment the hide file list count.
$hideListCount++;
}
}
elsif( $line =~ /^rename\s+(\S+)\s+(\S+)/i)
{
my $linesource = $1 ;
my $linedest = $2;
my $linekeyword = "rename";
&compareArrays($renameArray,$nonsisFileArray,$linesource,$linedest,$linekeyword);
}
elsif( $line =~ /^alias\s+(\S+)\s+(\S+)/i )
{
my $linesource = $1 ;
my $linedest = $2;
my $linekeyword = "alias";
&compareArrays($aliasArray,$nonsisFileArray,$linesource,$linedest,$linekeyword);
}
elsif( $line =~ /^(file|data)\s*=\s*/i || $line =~ /^\s*(zdriveimagename|sisfile)\s*=\s*/i )
{
# skip to next line.
next;
}
else
{
# push it on to the array.
unshift(@$datadriveArray,$line);
}
next;
}
# close the old oby files.
close(OLDDATA)or die "can't close $oldobyfile";
#write the array contents on to the file
print"* Updating $oldobyfile - final OBY file\n";
&writeDataToFile( $datadriveArray );
&writeDataToFile( $sisobyArray );
&writeDataToFile( $nonsisFileArray );
# close the new oby file.
close(NEWDATA)or die "can't close $newobyfile";
#rename the file.
rename( $newobyfile, $oldobyfile )or die "can't rename $newobyfile to $oldobyfile: $!";
}
# Traverse the entire given directory
# push all the folder contents on to an array.
sub TraverseDir
{
my($dir,$folderList,$sisFileContent,$rootdir) = @_;
#check the specified directory
chdir($dir) || die "Cannot chdir to $dir\n";
local(*DIR);
opendir(DIR, ".");#open current directory.
my $sourcedir;
my $destdir;
while (my $entry=readdir(DIR))
{
#skip, parent directory and current directory.
next if ($entry eq "." || $entry eq "..");
#check if it is a file
if( -f $entry )
{
my $sourcedir = $rootdir."\\".$folderList.$entry;
my $destdir = "$folderList".$entry;
my $sisSource;
my $sisdestination;
if(&checkRegCtlFiles($entry))
{
# check for any whitespace
if($sourcedir =~ m/ /)
{
# if yes, then append double quotes
$sisSource = "data="."\"".$sourcedir."\"";
}
else
{
# else dont append any double quotes for destination
$sisSource = "data=".$sourcedir;
}
# push the line on to the array.
push(@$sisFileContent,$sisSource."\t".'"'.$destdir.'"');
}
else
{
# check for any white space
if($sourcedir =~ m/ /)
{
# if yes, then append double quotes
$sisSource = "file="."\"".$sourcedir."\"";
}
else
{
# else dont append any double quotes for destination
$sisSource = "file=".$sourcedir;
}
# push the line on to the array.
push(@$sisFileContent,$sisSource."\t".'"'.$destdir.'"');
}
}
#else it's a directory
else
{
&TraverseDir($entry,$folderList.$entry."\\",$sisFileContent,$rootdir);
}
}
closedir(DIR);
chdir("..");
}
# write the data in to oby file by accessing appropriate array.
sub writeDataToFile
{
my ($array) = @_;
#get the array size.
my $arraySize = scalar(@$array);
for(my $i=0; $i<$arraySize ; $i++ )
{
#pop out the element to the respective obey file.
print NEWDATA pop(@$array)."\n";
}
}