internetradio2.0/cenrep/generate_cenrep_inifile.pl
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:01:53 +0300
changeset 0 09774dfdd46b
permissions -rw-r--r--
Revision: 201011 Kit: 201015

#
# 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 "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:
#
######################################
# Run with -h to get help
######################################
use strict;
use lib   ".";
use open OUT => ':raw';
use Win32::OLE qw(in with);
use Win32::OLE::Const 'Microsoft Excel';
use Cwd;
use Getopt::Long;
use File::Copy;
use Storable qw(fd_retrieve);
use excel_support;  # Own perl module that contains the reading of memory-sheets
use cenrep_keys;  # Own perl module that contains the reading of memory-sheets


use Data::Dumper;

# this is the bit mask that is put into the metadata in the ini-file, when
# backup is set on.
my $globalBackupValue = 0x01000000;

###########################################################################
###########################################################################
sub printStr
{
    my $to = shift;
    my $str = shift;

    for (my $i = 0; $i < length($str); $i++) 
    {
	printf $to "%s\0", substr($str,$i, 1);
    }
}

###########################################################################
###########################################################################
sub printNewLine
{
    my $to = shift;
    my $fileName = shift;
    
    print $to "\x0D\x00\x0A\x00";

    return;
}
#      # We need to close the file temporarely so that we can
#      # write a new line into it differently. It seems that
#      # unicode file name writing is somehow wrong in the 
#      # used perl versio (ActivePerl 5.8.4)
    
#      close $to;
#      # Writing the new line into the end of the line
#      open $to,">>$fileName";
#      binmode OUT;
#      print OUT chr(13);
#      print OUT chr(0);
#      print OUT chr(10);
#      print OUT chr(0);
#      close OUT;
    
#      # Opening the file again to
#  #    open(OUT,">>:encoding(UTF-16LE)",$fileName) || die "unable to open $fileName";
#      open(OUT,">>$fileName") || die "unable to open $fileName";
#  }

###########################################################################
# Function that gets a dir as parameter and reads the list of excel files from the
# given directory.
#
# Params: a directory name
#
# Return value: a reference to a list of filenames.
###########################################################################
sub getExcelFilesFromDir
{
    my $dir = shift;
    
    # the given dir should be relative to the dir, where the script is executed.
    if($dir !~ /^[\\\/]/ && $dir !~ /^[A-Za-z]:/)
    {
	$dir =  cwd . "\\$dir"; 
    }
    my @files;
    @files = <$dir\\*.xls >;
   
    return \@files;
}


###################################################
# Function that reads the file names from the given file.
# THe information is read from Column A and 1st empty row indicates
# end of input.
#
# Params: fileNameRead, refToExcelApp
###################################################
sub getExcelFilesFromFile
{
    my $file = shift;
    
    my @fileList;
    # ----------------------------------------------------------------  
    # Open the file
    # ----------------------------------------------------------------  
    open(IN,$file) || die "Unable to open: $file";

    #------------------------------------------------------------
    # Read file line by line
    #------------------------------------------------------------
    while(<IN>)
    {
	my $fileWithPath = $_;
	chomp($fileWithPath);

	if(! -f $fileWithPath)
	{
	    print STDERR "Warning: input file not found: $fileWithPath\n";
	}
	else
	{
	    push(@fileList,$fileWithPath);
	}
    }
	
    return \@fileList;
}

###################################################
###################################################
sub isRemoved
{
    my $platId = shift;
    my $platRel = shift;
    my $removed = shift;

    # If not defined => not removed
    if(! defined($removed))
    {
	return 0;
    }
   
    if($removed =~ /$platId\s+([0-9]+\.[0-9]+)/i)
    {
	my $rel = $1;
	if($rel <= $platRel)
	{
	    return 1;
	}
    }
    return 0;    
}
###################################################
# returns the official capa name from internal name.
# this is implemented since the capa names in cenrep keys
# migth not be the same as official names in the ini-file.
###################################################
sub getCapaValue
{
    my $formatNbr      = shift; # not used at the moment.
    my $refToCapaList  = shift;

    #########################
    # official way, caps as strings
    #########################

#      my $retVal = "";
#      my $isFirst = 1;
#      foreach my $capa (@$refToCapaList)
#      {
#  	next if($capa =~ /^\s*$/);
#  	if(!$isFirst)
#  	{
#  	    $retVal .= ",";
#  	}
#  	$retVal .= $capa;

#  	$isFirst = 0;
#      }

    #########################
    # Caps as strings
    #########################
    my $retVal = "";
    my @capaList;
    foreach my $capa (@$refToCapaList)
    {
	next if($capa =~ /^\s*$/);

	if( $capa =~ /ReadUserData/)
	{
	    push(@capaList,"ReadUserData"); 
	}
	elsif($capa =~ /WriteUserData/)
	{
	    push(@capaList,"WriteUserData");
	}
	elsif( $capa =~ /ReadDeviceData/)
	{
	    push(@capaList,"ReadDeviceData");
	}
	elsif($capa =~ /WriteDeviceData/)
	{
	    push(@capaList,"WriteDeviceData");
	}
	elsif($capa =~ /NetworkControl/)
	{
	    push(@capaList,"NetworkControl");
	}
	elsif($capa =~ /NetworkServices/)
	{
	    push(@capaList,"NetworkServices");
	} 
	elsif($capa =~ /Local Services/)
	{
	    push(@capaList,"LocalServices");
	} 
	elsif($capa =~ /Location/)
	{
	    push(@capaList,"Location");
	} 
	elsif($capa =~ /ProtServ/)
	{
	    push(@capaList,"ProtServ");
	} 
	elsif($capa =~ /DRM/)
	{
	    push(@capaList,"DRM");
	} 
	elsif($capa =~ /SwEvent/)
	{
	    push(@capaList,"SwEvent");
	} 
	elsif($capa =~ /PowerMgmt/)
	{
	    push(@capaList,"PowerMgmt");
	} 
	elsif($capa =~ /AllFiles/)
	{
	    push(@capaList,"AllFiles");
	} 
	elsif($capa =~ /DiskAdmin/)
	{
	    push(@capaList,"DiskAdmin");
	} 
	elsif($capa =~ /MultiMediaDD/)
	{
	    push(@capaList,"MultimediaDD");
	} 
	elsif($capa =~ /CommDD/)
	{
	    push(@capaList,"CommDD");
	} 
	elsif($capa =~ /TrustedUI/)
	{
	    push(@capaList,"TrustedUI");
	} 
	elsif($capa =~ /TCB/)
	{
	    push(@capaList,"TCB");
	} 
	elsif($capa =~ /AlwaysPass/  || $capa =~ /None/)
	{
	    push(@capaList,"alwayspass");
	} 
	elsif($capa =~ /UserEnvironment/)
	{
	    push(@capaList,"UserEnvironment");
	} 
	elsif($capa =~ /SurroundingsDD/)
	{
	    push(@capaList,"SurroundingsDD");
	} 
    }
    
    return join(",",@capaList);

}
###################################################
# 3rd param syntax:
# <release> 
#     => { 
#        "R" => (<capa1ForReading>,<capa2ForReading>)
#        "W" => (<capa1ForWriting>,<capa2ForWriting>)
#        "value" => <value>
#        "rfs"  => <0/1>
#        "backup"  => <0/1>
#         }
#  
###################################################
sub getConfig
{
    my $platId = shift;
    my $platRel = shift;
    my $refToHash = shift;

    my $currRel = "0";
    my $currRef = undef;
    foreach my $plat (sort keys %$refToHash)
    {
	if($plat =~ /$platId\s+([0-9]+\.[0-9]+)/i)
	{
	    my $tentativeRel = $1;
	    if($tentativeRel > $currRel && $tentativeRel <= $platRel)
	    {
		$currRel = $tentativeRel;
		$currRef = $$refToHash{$plat};
	    }
	}
    }
#      if($currRel > 0)
#      {
#  	print $$refToHash{$currRel}, "a\n";
#  	return $$refToHash{$currRel};
#      }
    return $currRef;
}

###########################################################################
# Main function, 
###########################################################################
sub readConfig
{
    my $refToExcelFiles = shift;
    my $refToExcel = shift;
    
    my %reshHash;
    my $refToWorkSheet;
    
    # Loop through each found excel sheet. This will open one file after each other
    # and parse information into the hashes defined above.
    foreach my $file ( @{$refToExcelFiles} ) 
    {
	print "   Reading: $file\n";

	# ----------------------------------------------------------------  
	# Open the file
	# ----------------------------------------------------------------  
	my $refToWb = openWorkbook( $file,$refToExcel);

	# ----------------------------------------------------------------  
	# Check, that the template version is the one we support. If not
	# the file is skipped and warning is written to user.
	# ----------------------------------------------------------------  
#  	if( isSupported($refToWb) == 0)
#  	{
#  	    # "delete" the workbooks, this closes the excel application
#  	    undef $$refToWb;
#  	    undef $refToWb;
#  	    print STDERR "Warning: Unsupported template version in file: $file\n";
#  	    next;
#  	}

	
	# ----------------------------------------------------------------  
	# Read the information from the worksheets
	# ----------------------------------------------------------------
	for( my $i = 0; $i < $$refToWb->Worksheets->Count; $i++)
	{
	    my $workSheet = $$refToWb->WorkSheets($i + 1);
	    $refToWorkSheet = getWorkSheet( $refToWb,$workSheet->Name);
	    readCentrepKeyInfo( $refToWorkSheet,\%reshHash);
	}
	# "delete" the workbooks, this closes the excel application
	$$refToWb->Close(0);
	undef $$refToWb;
	undef $refToWb;
    }
    return \%reshHash;
}
###########################################################################
###########################################################################
sub getKeyType
{
    my $key = shift;

    return "string" if($key =~ /str/i);
    return "int" if($key =~ /int/i);
    return "real" if($key =~ /real/i);
    return "binary" if($key =~ /bin/i);

    return "unknown_type";
}


###########################################################################
# Prints the Key and key type into the given output.
# The format in which the key is printed is format specific.
###########################################################################
sub printKey
{
    my $to = shift;
    my $formatNbr = shift;
    my $key = shift;
    my $keyType = shift;

    $key =~ s/0x(0*)/0x/g;
    # Add 0 if the key value is "0x" (cases, where the id == 0)
    $key .= "0" if $key =~ /0x\s*$/;
    printStr $to, $key . " " . $keyType . " ";

    return;
}

###########################################################################
# Prints the capabilities into the given output.
# The format in which the capabilities are printed is format specific.
###########################################################################
sub printCapa
{
    my $to = shift;
    my $formatNbr = shift;
    my $refToCapaList = shift;
    my $prefix = shift;
    my $alwaysFail = shift;

    if($formatNbr > 1)
    {
	if($alwaysFail && $formatNbr > 3)
	{
	    printStr \*OUT, " $prefix=alwaysfail";
	}
	elsif(defined($refToCapaList) && scalar(@$refToCapaList) > 0)
	{
	    my $capaStr = getCapaValue($formatNbr,$refToCapaList);
	    printStr \*OUT, " $prefix=$capaStr" if($capaStr);
	}
    }
}

###########################################################################
# Prints the Sid  capabilities into the given output.
# The format in which the capabilities are printed is format specific.
###########################################################################
sub printSidCapa
{
    my $to = shift;
    my $formatNbr = shift;
    my $refToCapaList = shift;
    my $prefix = shift;

    if($formatNbr > 1)
    {
	if(defined($refToCapaList) && scalar(@$refToCapaList) > 0)
	{
	    # Only 1 SID is allowed
	    printStr \*OUT, " $prefix=$$refToCapaList[0]";
	}
    }
}

###########################################################################
# Prints the information about ranges
###########################################################################
sub printPlatSec
{
    my $to = shift;
    my $formatNbr = shift;
    my $refToUidSpecificHash = shift;
    my $refToRangesHash = shift;
    my $fileName = shift;
    my $addDefCaps = shift;

    #-------------------------------
    # UID specific (default capabilities)
    #-------------------------------
    # we need to know if write / read was specified.
    # if not and addDefCaps is defined => then be add the 
    # default alwayspass to the file
    my $readSpecified = 0;
    my $writeSpecified = 0;

    ###############################
    # RSid-capa writing (format specific)
    ###############################
    my $refToCapaList = $$refToUidSpecificHash{"RSid"};
    printSidCapa($to,$formatNbr,$refToCapaList,"sid_rd");
    $readSpecified += scalar(@$refToCapaList) if defined($refToCapaList);
    
    ###############################
    # R-capa writing (format specific)
    ###############################
    $refToCapaList = $$refToUidSpecificHash{"R"};
    printCapa($to,$formatNbr,$refToCapaList,"cap_rd",0);
    $readSpecified = scalar(@$refToCapaList) if defined($refToCapaList);
    
    # Add def caps if no caps were defined
    if($addDefCaps > 0 && $readSpecified < 1)
    {
	printStr \*OUT, " cap_rd=alwayspass";

    }

    ###############################
    # WSid-capa writing (format specific)
    ###############################
    $refToCapaList = $$refToUidSpecificHash{"WSid"};
    printSidCapa($to,$formatNbr,$refToCapaList,"sid_wr");
    $writeSpecified += scalar(@$refToCapaList) if defined($refToCapaList);
    
    ###############################
    # W-capa writing (format specific)
    ###############################
    $refToCapaList = $$refToUidSpecificHash{"W"};
    printCapa($to,$formatNbr,$refToCapaList,"cap_wr",0);
    $writeSpecified = scalar(@$refToCapaList) if defined($refToCapaList);
    
    # Add def caps if no caps were defined
    if($addDefCaps > 0 && $writeSpecified < 1)
    {
	printStr \*OUT, " cap_wr=alwayspass";

    }

    printNewLine($to,$fileName);
    
    #-------------------------------
    # Ranges
    #-------------------------------
    foreach my $rangeFrom (keys %$refToRangesHash)
    {
	my $refToRangeFromHash = $$refToRangesHash{$rangeFrom};

	foreach my $rangeTo (keys %$refToRangeFromHash)
	{
	    my $refToRangeToHash = $$refToRangeFromHash{$rangeTo};

	    printStr $to, $rangeFrom . " " .$rangeTo;
	    
	    ###############################
	    # RSid-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToRangeToHash{"RSid"};
	    printSidCapa($to,$formatNbr,$refToCapaList,"sid_rd");
	    
	    ###############################
	    # R-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToRangeToHash{"R"};
	    printCapa($to,$formatNbr,$refToCapaList,"cap_rd",0);
	
	    ###############################
	    # WSid-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToRangeToHash{"WSid"};
	    printSidCapa($to,$formatNbr,$refToCapaList,"sid_wr");
	    
	    ###############################
	    # W-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToRangeToHash{"W"};
	    printCapa($to,$formatNbr,$refToCapaList,"cap_wr",0);
	    
	    printNewLine($to,$fileName);
	}
    }    
}

###########################################################################
# Prints the information about metadata
###########################################################################
sub printMetadata
{
    my $to = shift;
    my $formatNbr = shift;
    my $refToUidSpecificHash = shift;
    my $refToRangesHash = shift;
    my $fileName = shift;

    #-------------------------------
    # UID specific metadata
    #-------------------------------

    my $metaData = 0;
    if($$refToUidSpecificHash{"backup"})
    {
	$metaData += $globalBackupValue;
    }
    printStr $to, " $metaData";
    printNewLine($to,$fileName);

    
    #-------------------------------
    # Ranges
    #-------------------------------
    foreach my $rangeFrom (keys %$refToRangesHash)
    {
	my $refToRangeFromHash = $$refToRangesHash{$rangeFrom};

	foreach my $rangeTo (keys %$refToRangeFromHash)
	{
	    my $refToRangeToHash = $$refToRangeFromHash{$rangeTo};

	    printStr $to, $rangeFrom . " " .$rangeTo;

	    my $metaData2 = 0;
	    if($$refToRangeToHash{"backup"})
	    {
		$metaData2 += $globalBackupValue;
	    }
	    printStr $to, " $metaData2";
	    printNewLine($to,$fileName);
	}    
    }
}

###########################################################################
# Function that generates a text file for the Restore factory settings.
# This file 
###########################################################################
sub generateRfsFile
{
    my $reshHash = shift;
    my $rfsFileWithPath = shift;

    open(OUT,">$rfsFileWithPath") || die "unable to open $rfsFileWithPath for writing";
    print OUT "\xFF\xFE";

    foreach my $uid (keys %$reshHash)
    {
	my $refToUidHash = $$reshHash{$uid};
	$uid =~ s/^0x0*//g;
	$uid = 0 if $uid =~ /^$/;
	my $refToUidSpecificHash = $$refToUidHash{"uid_specific"};

	# Uid specific rfs overwrites the key specific values
	# Thus if this is set to yes => we can skip key specific values
	if($$refToUidSpecificHash{"rfs"})
	{	    
	    printStr \*OUT, "CR $uid";
	    printNewLine(\*OUT,$rfsFileWithPath);
	    next;
	}

	# If we get here => uid was not set to yes for RFS.
	# now we loop through each ke
	########################
	# print each key into the file.
	########################
	my $refToKeysHash = $$refToUidHash{"keys"};
	my $isFirstInUid = 1;
	foreach my $key (sort keys %$refToKeysHash)
	{		
	    my $refToKeyHash = $$refToKeysHash{$key};

	    # Check, if the key was restored in RFS. 	    
	    if($$refToKeyHash{"rfs"})
	    {
		# If this is the 1st key for this UI, then
		# we print the keyword (CR) and the uid into the
		# file.
		if($isFirstInUid)
		{
		    $isFirstInUid = 0;
		    printStr \*OUT, "CR $uid";
		    
		}
		
		# print the key into the file (after some modifications)
		$key =~ s/^0x0*//g;
		$key = 0 if $key =~ /^$/;
		printStr \*OUT, " $key";
	    }
	}
	# Print a newline if (and only if) there was keys that had rfs-flag
	# on.
	if(! $isFirstInUid)
	{
	    printNewLine(\*OUT,$rfsFileWithPath);
	}
    }  
    close OUT;
}

###########################################################################
# Function that generates all the ini (txt)-files for the central repository.
# There are multiple formats, which are supported at the moment, since the
# development in ongoing and syntax is still a little but unknown.
###########################################################################
sub generateIniFiles
{
    my $reshHash = shift;
    my $dirname = shift;
    my $formatNbr = shift;
    my $addDefCaps = shift;

    my $iniFileCount = 0;
    my $keyCount = 0;

    foreach my $uid (keys %$reshHash)
    {
	my $refToHash = $$reshHash{$uid};
	$refToHash = $$refToHash{"keys"};
	my $refToRangeHash = $$refToHash{"ranges"};
	if(scalar(keys %$refToHash) < 1 && scalar(keys %$refToRangeHash))
	{
	    # Skip uid, if no keys and ranges
	    next;
	}
	$iniFileCount++;

	##################################
	# Filename syntax is "uid.txt" without the 0x in the begining 
	##################################
	my $fileName = "$uid.txt";
	$fileName =~ s/^0x//i;
			     
	# Add dir name into the filename. 
	if($dirname !~ /^\s*$/)
	{
	    my $tmpFileName = $fileName;
	    $fileName = $dirname;
	    if($dirname !~ /[\\\/]$/)
	    {
		$fileName .=  "\\";
	    }
	    $fileName .= $tmpFileName;
	}

	########################
        # Copy the start of the file into the new name
	# (note that this migth become format specific, 
	#  but is not at the moment).
	########################
	my $templateName = "cenrep_start.ini";
	    
	copy($templateName,$fileName) or die "Copy failed: $! : $fileName";
	open(OUT,">>$fileName") || die "unable to open $fileName";
	########################
	# Print the [owner] section
	########################
	if($formatNbr > 2)
	{
	    my $refToUidHash = $$reshHash{$uid};
	    my $refToUidSpecificHash = $$refToUidHash{"uid_specific"};

	    if($$refToUidSpecificHash{"owner"} !~ /^\s*$/)
	    {
		printStr \*OUT, "[owner]";
		printNewLine(\*OUT,$fileName);
		printStr \*OUT, $$refToUidSpecificHash{"owner"};
		printNewLine(\*OUT,$fileName);
	    }	    
	}

	########################
	# Print the [defaultmeta] section
        # Note that depending on the format
        # nbr the metadata has to be before or after
        # platsec-section.
	########################
	if($formatNbr > 3 )
	{
	    printStr \*OUT, "[defaultmeta]";
	    printNewLine(\*OUT,$fileName);

	    my $refToUidHash = $$reshHash{$uid};
	    printMetadata(\*OUT,$formatNbr,$$refToUidHash{"uid_specific"},
			  $$refToUidHash{"ranges"},$fileName);
	}
        
	########################
	# Print the [PlatSec] section
	########################
	if($formatNbr > 1)
	{
	    printStr \*OUT, "[platsec]";
	    printNewLine(\*OUT,$fileName);
    
	    my $refToUidHash = $$reshHash{$uid};
	    printPlatSec(\*OUT,$formatNbr,$$refToUidHash{"uid_specific"},
			$$refToUidHash{"ranges"},$fileName,$addDefCaps);
	}
	########################
	# Print the [metadata] section
	########################
	if($formatNbr eq 3)
	{
	    printStr \*OUT, "[metadata]";
	    printNewLine(\*OUT,$fileName);

	    my $refToUidHash = $$reshHash{$uid};
	    printMetadata(\*OUT,$formatNbr,$$refToUidHash{"uid_specific"},
			  $$refToUidHash{"ranges"},$fileName);
	}

	########################
	# Print the [Main] section
	########################
	if($formatNbr > 0)
	{
	    printStr \*OUT, "[Main]";
	    printNewLine(\*OUT,$fileName);
	}

	########################
	# print each key into the file.
	########################
	foreach my $key (sort keys %$refToHash)
	{		
	    $keyCount++;
	    my $refToHash2 = $$refToHash{$key};

	    ###############################
	    # Writing the key and key type. 
	    # This is format specific.
	    ###############################
	    printKey(\*OUT,$formatNbr,$key,getKeyType($$refToHash2{"key type"}));

	    ###############################
	    # Write the value into the file
	    ###############################

	    # Strings are always enclosed with \". Also empty binary value is also enclosed
	    # such way
 	    if($$refToHash2{"key type"} =~ /str/i ) 
	    {
		printStr \*OUT, "\"";
	    }
	    printStr \*OUT, $$refToHash2{"value"}; 
 	    if($$refToHash2{"key type"} =~ /str/i) 
	    {
		printStr \*OUT, "\"";
	    }

            if ($$refToHash2{"key type"} =~ /bin/i && $$refToHash2{"value"} =~ /^\s*$/)
            {
                printStr \*OUT, "00";
            }

	    ###############################
	    # Generating the metadata and adding it into the file
	    ###############################
	    my $metaData = 0;
	    if($$refToHash2{"backup"})
	    {
		$metaData += $globalBackupValue;
	    }
	    printStr \*OUT, " $metaData";

	    # Note, according to the cenrep specification, then read access has to be
	    # before the write access.

	    ###############################
	    # RSid-capa writing (format specific)
	    ###############################
	    my $refToCapaList = $$refToHash2{"RSid"};
	    printSidCapa(\*OUT,$formatNbr,$refToCapaList,"sid_rd");

	    ###############################
	    # R-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToHash2{"R"};
	    printCapa(\*OUT,$formatNbr,$refToCapaList,"cap_rd",0);

	    ###############################
	    # WSid-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToHash2{"WSid"};
	    printSidCapa(\*OUT,$formatNbr,$refToCapaList,"sid_wr");

	    ###############################
	    # W-capa writing (format specific)
	    ###############################
	    $refToCapaList = $$refToHash2{"W"};
	    printCapa(\*OUT,$formatNbr,$refToCapaList,"cap_wr",$$refToHash2{"read-only"});

	    ##########################################
	    ##########################################
	    ##########################################
	    ##########################################
	    printNewLine(\*OUT,$fileName);
	}
	close OUT;
    }

    print "Ini file count = $iniFileCount\n";
    print "Key count      = $keyCount\n";
}

###########################################################################
# Shows help.
#
# Params: -
#
# Return: -
#
###########################################################################
sub usage
{
    $0 =~ /([0-9a-zA-Z\_\.]+)$/;
    my $filename = $1;
    print "\n";
    print "\n";
    print "\n";
    print "This script is intended to be used to generate ini-files for Central Repository\n";
    print "based on the information in the cenrep key excel-sheet(s). These sheets define\n";
    print "the content of the ini-files.\n";
    print "\n";
    print "Rough discruption on how the values for the ini-files are determinated:\n";
    print "1) Content of sheets identified by -d or -s are read.\n";
    print "   (alternatively -b can be used a storable file, where the sheet info\n";
    print "    is already in binary format)\n";
    print "2) From sheets read in step 1 the information is parsed based on the\n";
    print "   information specified by -p, -r and -v\n";
    print "3) [optional] Default values specified by the steps 1 and 2 can be\n";
    print "    overriden by defining information in other sheets, specified by parameters\n";
    print "    -vd,-vs,-vb and -vv, \n";
    print "\n";
    print "\n";
    print "Usage:\n";
    print "  $filename [-h|-help] [-fh]\n";
    print "                [-p <platId>] -r <platRel> [-v <variantName]\n";
    print "                (-d <dirName> | -s <sourceFilename> | -b <storableFilename>)\n";
    print "                [ -rd <resultDir>]\n";
    print "                [ (-vd <variantDirName> | -vs <sourceFilename> | -vb <storableFilename>)\n";
    print "                  [-vv <variantsVariantName>]]\n";
    print "                [-f <formatNbr> ]\n";
    print "                [-dc ]\n";
    print "                [-rfs <dirName> [-noini]]\n";
    print "\n";
    print "Options:\n";
    print " -h                  : Show this help\n";
    print " -help               : Show this help\n";
    print " -fh                 : Show the help about supported formats.\n";
    print " -p <platId>         : The identifier specifying platform. Optional. Default value: S60\n"; 
    print "                       to the directory where the mem-sheets exist.\n";
    print " -r <platRel>        : The platform number. For example: 3.0\n";
    print " -rd <resultDir>     : The path, where the generated ini-files are written.\n";
    print "                        Default: current directory\n";
    print " -v <variantName>    : The variant name. Optional. Default value: \"\" == no variant.\n";
    print "                       The names are not fixed in the script. The same names has to be\n";
    print "                       used as supported by the excel sheet.\n";
    print " -d <dirName>        : The dir, which contains the sheets, which are read. Relative path to the\n";
    print "                       current dir or absoluth path. NOTE: the dir name can't contain any spaces.\n";
    print " -s <sourceFilename>       : The text filename, which contains sheet name with absoluth\n";
    print "                             path names (1/row)\n";
    print " -b <storableFilename>  : the storable file name, which contains the same information as the\n";
    print "                          key sheets. ( this can be generated with gather_cenrep_to_storable.pl)\n";
    print " -vd <variantDirName>      : Same as -d, but for variant information\n";
    print "                             (see rough description above) Optional.\n";
    print " -vs <sourceFilename>      : Same as -s, but for variant information\n";
    print "                              (see rough description above) Optional.\n";
    print " -vb <storableFilename>  : the storable file name, which contains the same information as the\n";
    print "                          variant key sheets.\n";
    print " -vv <variantsVariantName> : Same as -v, but for variant information\n";
    print "                              (see rough description above) Optional.\n";
    print " -f <formatNbr>          : the format type that is generated. (see list of formats with -fh)\n";
    print " -dc                     : adds alwayspass as default capabilities for UID namespace if non \n";
    print "                              specified (also applies to certain formats)\n";
    print " -rfs <dirName>        : The dir to which cenrep.txt-file is generated. This file\n";
    print "                         contains info for Restore Factory Settings\n";
    print " -noini                : used only with -rfs-option. If specified, only RFS file generated,\n";
    print "                          no ini-files.\n";
    print "\n";
    print "\n";
    print "You have specify either -d or -s, but not both at the same time.\n";
    print "You can specify either -vd or -vs, but not both at the same time.\n";
    print "\n";
    print "\n";
}


###########################################################################
# Shows format help.
#
# Params: -
#
# Return: -
#
###########################################################################
sub formatHelp
{
    $0 =~ /([0-9a-zA-Z\_\.]+)$/;
    my $filename = $1;
    print "\n";
    print "\n";
    print "Supported formats (default format is 4):\n";
    print "   0 : Format, where there are no capabilities generated for the keys.\n";
    print "       Supported is key (as hex), type, value and metadata.\n";
    print "       No \"[Main]\"-tag is included into the ini-file.\n";
    print "       (a temporary fix so that testing can continue).\n";
    print "   1 : Format 0 + \"[Main]\"-tag is included into the ini-file.\n";
    print "       (Symbian w48 and earlier builds).\n";
    print "\n";
    print "   2 : Format 1 + in addition  capabilities are written in text format.\n";
    print "       Supported is key (as hex), type, value, metadata and read/write capabilities in text format.\n";
    print "       (Symbian w50 and later builds).\n";
    print "\n";
    print "   3 : Format 3 + in addition owner and metadata are written in text format.\n";
    print "       Supported is key (as hex), type, value, metadata and read/write capabilities in text format.\n";
    print "       (Symbian w?? and later builds).\n";
    print "\n";
    print "   4 : Format 4 + in addition alwaysfail-keyword used in ini-file.\n";
    print "       (Symbian w10 and later builds).\n";
    print "\n";
    print "\n";
    print "\n";

}
###########################################################################
# Parses the command line parameters from ARGV
#
# Params: -
#
# Return: -		    
#
###########################################################################
sub parseCmdLine
{
    my $platId = "S60";
    my $platRel = "";
    my $varName = "";
    my $sheetDirname = "";
    my $sheetFilename = "";
    my $storableFilename = "";
    my $resultDirname = "";
    my $varNameVariant = "";
    my $sheetDirnameVariant = "";
    my $sheetFilenameVariant = "";
    my $storableFilenameVariant = "";
    my $formatNbr = -1;
    my $addDefCaps = 0;
    my $rfsDir = "";
    my $noIni = 0;
    my $showHelp = 0;
    my $showFormatHelp = 0;

    if( ! GetOptions('p:s'      => \$platId,
		     'r:s'      => \$platRel,
		     'v:s'      => \$varName,
		     'd:s'      => \$sheetDirname,
		     's:s'      => \$sheetFilename,
		     'b:s'      => \$storableFilename,
		     'rd:s'     => \$resultDirname,
		     'vv:s'     => \$varNameVariant,
		     'vd:s'     => \$sheetDirnameVariant,
		     'vs:s'     => \$sheetFilenameVariant,
		     'vb:s'     => \$storableFilenameVariant,
		     'f:i'      => \$formatNbr,
		     'dc'       => \$addDefCaps,
		     'rfs:s'    => \$rfsDir,
		     'noini'    => \$noIni,
		     'h'        => \$showHelp,
		     'help'     => \$showHelp,
		     'fh'       => \$showFormatHelp,
		     '<>'       => \&usage))
    {
	usage();
	exit(1);
    }
    

    ####################################
    # Format number handling.
    ####################################
    # Set default format number, if not specified.
    if( $formatNbr < 0)
    {
	$formatNbr = 4;
    }
    elsif( $formatNbr > 4)
    {
	print "\nError: Invalid format number: $formatNbr.\n";
	$showFormatHelp = 1;
    }

    if($showFormatHelp)
    {
	formatHelp();
	exit(1);
    }
    if($showHelp)
    {
	usage();
	exit(1);
    }



    ####################################
    # Checking other parameters
    ####################################
    my $error = 0;
    if(    ($sheetDirname ne "" and $sheetFilename ne "") 
	or ($sheetDirname ne "" and -b $storableFilename ne "")
	or ($sheetFilename ne "" and -b $storableFilename ne ""))
    {
	print "\nError: The -s, -d and -b arguments can't be specified at the same time.\n";
	$error = 1;
    }
    elsif($sheetDirname eq "" and $sheetFilename eq "" and $storableFilename eq "")
    {
	print "\n\nError: You have to specify either the -d or -s or -b argument.\n";
	$error = 1;
    }

    if(   ($sheetDirnameVariant ne "" and $sheetFilenameVariant ne "")
       or ($sheetDirnameVariant ne "" and $storableFilenameVariant ne "")
       or ($storableFilenameVariant ne "" and $sheetFilenameVariant ne "")
	    )
    {
	print "\nError: The -vs and -vd  and -vb arguments can't be specified at the same time.\n";
	$error = 1;
    }

    if($platRel eq "")
    {
	print "\nError: You have to specify -r parameter.\n";
	$error = 1;
    }
    
    if($error)
    {
	usage();
	exit(1);
    }
    elsif($showHelp)
    {
	usage();
    }

    return ($platId,$platRel,$varName,$sheetDirname,$sheetFilename,$storableFilename,
	    $resultDirname,$varNameVariant,
	    $sheetDirnameVariant,$sheetFilenameVariant,$storableFilenameVariant,$formatNbr,
	    $addDefCaps,$rfsDir,$noIni);
}

###########################################################################
#
# The format of the returned hash is:
# NOTE: Still one bug, onge a range/key  has been defined it can't be removed 
#  {
#  <uid> => 
#    {
#    "uid_specific"   
#           = > {
#               "R" => (<capa1ForReading>,<capa2ForReading>)
#               "W" => (<capa1ForWriting>,<capa2ForWriting>)
#               "RSid" => (<sidForReading>)
#               "WSid" => (<sidForWriting>)
#               "owner"  => <someHexValue>
#               "rfs"  => <0/1>
#               "backup"  => <0/1>
#               }
#    "ranges"   
#           = > {
#            <fromRange>
#              => {
#                <toRange>
#                 => {
#                    "R" => (<capa1ForReading>,<capa2ForReading>)
#                     "W" => (<capa1ForWriting>,<capa2ForWriting>)
#                     "RSid" => (<sidForReading>)
#                     "WSid" => (<sidForWriting>)
#                     "rfs"  => <0/1>
#                     "backup"  => <0/1>       
#                     }
#                  }        
#               }
#    "keys" => {
#              <keyInt> 
#                   => {
#                      "read-only" => <0/1>
#                      "key type" => <bin/int/str/bool>
#                      "R" => (<capa1ForReading>,<capa2ForReading>)
#                      "W" => (<capa1ForWriting>,<capa2ForWriting>)
#                      "RSid" => (<sidForReading>)
#                      "WSid" => (<sidForWriting>)
#                      "value" => <value>
#                      "rfs"  => <0/1>
#                      "backup"  => <0/1>
#                       }
#                } # keys
###########################################################################
sub generateConfig
{
    my $refToResHash = shift;     # The generated configuration
    my $reftoConfigHash = shift;  # from where the configuration is generated from
    my $platId = shift;
    my $platRel = shift;
    my $varName = shift;

    if($varName =~ /^\s*$/)
    {
	# same as in cenrep_keys.pm
	$varName = "default";
    }

    # See syntax of reftoConfigHash from the documentation of
    # readCentrepKeyInfo
    my $refToHash;
    foreach my $uid (keys %$reftoConfigHash)
    {
	my $tmpUidResHash = addHash($uid,$refToResHash);
	my $refToUidConfigHash = $$reftoConfigHash{$uid};

	##########################################
	# Adding UID information
	##########################################
	my $refToUidSpecificResHash = addHash("uid_specific",$tmpUidResHash);

	my $refToUidSpecificConfigHash = $$refToUidConfigHash{"uid_specific"};
	my $refToUidSpecificVariantConfigHash = undef;

	#--------------------------------------------------
	# now check, if there is variant specific configuration
	#--------------------------------------------------
	if(defined($$refToUidSpecificConfigHash{$varName}))
	{
	    $refToUidSpecificVariantConfigHash 
		= getConfig($platId,$platRel,
			    $$refToUidSpecificConfigHash{$varName});
	}
	#--------------------------------------------------
	# if not found, then try to get default configuration
	#--------------------------------------------------
	if(!defined($refToUidSpecificVariantConfigHash) && $varName ne "default")
	{
	    $refToUidSpecificVariantConfigHash 
		= getConfig($platId,$platRel,
			    $$refToUidSpecificConfigHash{"default"});	    
	}
	#--------------------------------------------------
	# if we found configuration then add it to the hash
	#--------------------------------------------------
	if(defined($refToUidSpecificVariantConfigHash))
	{
	    $$refToUidSpecificResHash{"rfs"} = $$refToUidSpecificVariantConfigHash{"rfs"};
	    $$refToUidSpecificResHash{"backup"} = $$refToUidSpecificVariantConfigHash{"backup"};
	    $$refToUidSpecificResHash{"R"} = $$refToUidSpecificVariantConfigHash{"R"};
	    $$refToUidSpecificResHash{"W"} = $$refToUidSpecificVariantConfigHash{"W"};
	    $$refToUidSpecificResHash{"RSid"} = $$refToUidSpecificVariantConfigHash{"RSid"};
	    $$refToUidSpecificResHash{"WSid"} = $$refToUidSpecificVariantConfigHash{"WSid"};
	    $$refToUidSpecificResHash{"owner"} = $$refToUidSpecificVariantConfigHash{"owner"};
	}	    
	##########################################
	# Adding range information
	##########################################
	my $refToRangesResHash = addHash("ranges",$tmpUidResHash);

	my $refToRangesConfigHash = $$refToUidConfigHash{"ranges"};
	foreach my $rangeFrom (keys %$refToRangesConfigHash)
	{
	    my $refToRangeCommonConfigHash = ${$$refToRangesConfigHash{$rangeFrom}}{"common"};
	    # 1st check, if the key belongs to this release
	    if(isRemoved($platId,$platRel,$$refToRangeCommonConfigHash{"removed"}))
	    {
		next;
	    }

	    my $refToRangesToConfigHash = ${$$refToRangesConfigHash{$rangeFrom}}{"to"};
	    foreach my $rangeTo (keys %$refToRangesToConfigHash)
	    {
		my $refToSingleRangeToConfigHash 
		    = $$refToRangesToConfigHash{$rangeTo};
		my $refToRangeToVariantConfigHash = undef;
		#--------------------------------------------------
		# now check, if there is variant specific configuration
		#--------------------------------------------------
		if(defined($$refToSingleRangeToConfigHash{$varName}))
		{
		    $refToRangeToVariantConfigHash
			= getConfig($platId,$platRel,
				    $$refToSingleRangeToConfigHash{$varName});
		}
		#--------------------------------------------------
		# if not found, then try to get default configuration
		#--------------------------------------------------
		if(!defined($refToRangeToVariantConfigHash) && $varName ne "default")
		{
		    $refToRangeToVariantConfigHash
			= getConfig($platId,$platRel,
				    $$refToSingleRangeToConfigHash{"default"});	    
		}
		#--------------------------------------------------
		# if we found configuration then add it to the hash
		#--------------------------------------------------
		if(defined($refToRangeToVariantConfigHash))
		{
		    my $refRangeVariantResHash  = addHash($rangeFrom,$refToRangesResHash);
		    $refRangeVariantResHash  = addHash($rangeTo,$refRangeVariantResHash);
		    $$refRangeVariantResHash{"rfs"} = $$refToRangeToVariantConfigHash{"rfs"};
		    $$refRangeVariantResHash{"backup"} = $$refToRangeToVariantConfigHash{"backup"};
		    $$refRangeVariantResHash{"R"} = $$refToRangeToVariantConfigHash{"R"};
		    $$refRangeVariantResHash{"W"} = $$refToRangeToVariantConfigHash{"W"};
		    $$refRangeVariantResHash{"RSid"} = $$refToRangeToVariantConfigHash{"RSid"};
		    $$refRangeVariantResHash{"WSid"} = $$refToRangeToVariantConfigHash{"WSid"};
		}	
	    }
	}    
	##########################################
	# Adding key values
	##########################################
	my $tmpKeysResHash = addHash("keys",$tmpUidResHash);

	$refToHash = $$reftoConfigHash{$uid};
	$refToHash = $$refToHash{"keys"};
	foreach my $key (keys %$refToHash)
	{
	    my $refToCommonHash = ${$$refToHash{$key}}{"common"};
	    # 1st check, if the key belongs to this release
	    if(isRemoved($platId,$platRel,$$refToCommonHash{"removed"}))
	    {
		next;
	    }
	    #--------------------------------------------------
	    # now check, if there is variant specific configuration
	    #--------------------------------------------------
	    my $refToRelHash = ${$$refToHash{$key}}{"release"};
	    my $refToKeyConfigHash;
	    if(defined($$refToRelHash{$varName}))
	    {
		$refToKeyConfigHash = getConfig($platId,$platRel,
						$$refToRelHash{$varName});
	    }
	    #--------------------------------------------------
	    # if not found, then try to get default configuration
	    #--------------------------------------------------
	    if(!defined($refToKeyConfigHash) && $varName ne "default")
	    {
		$refToKeyConfigHash 
		    = getConfig($platId,$platRel,
				$$refToRelHash{"default"});	    
	    }
	    #--------------------------------------------------
	    # if we found configuration then add it to the hash
	    #--------------------------------------------------
	    if(defined($refToKeyConfigHash))
	    {
		my $keyResHash = addHash($key,$tmpKeysResHash);
		$$keyResHash{"read-only"} = $$refToCommonHash{"read-only"};
		$$keyResHash{"key type"} = $$refToCommonHash{"key type"};
		$$keyResHash{"value"} = $$refToKeyConfigHash{"value"};
		$$keyResHash{"rfs"} = $$refToKeyConfigHash{"rfs"};
		$$keyResHash{"backup"} = $$refToKeyConfigHash{"backup"};
		$$keyResHash{"R"} = $$refToKeyConfigHash{"R"};
		$$keyResHash{"W"} = $$refToKeyConfigHash{"W"};
		$$keyResHash{"RSid"} = $$refToKeyConfigHash{"RSid"};
		$$keyResHash{"WSid"} = $$refToKeyConfigHash{"WSid"};
	    }	    
	}
    }
}

###########################################################################
# reads either default config or variant config into the result hash.
# Note that the variant hash can't delete any keys, just override them.
###########################################################################
sub readSingleConfig
{
    my $refToExcel      = shift;
    my $sheetDirname    = shift;
    my $sheetFilename   = shift;
    my $storableFilename = shift;
    my $refToResultHash = shift;
    my $platId          = shift;
    my $platRel         = shift;
    my $varName         = shift;
    
    #-----------------------------------------------------------------
    # There are 2 options how the user can give the if-sheet names handled:
    # 1) He gives the directory where all files are located
    # 2) He gives an excel sheet, which contains all the files in column A.
    #-----------------------------------------------------------------
    my $refToExcelFilesList;

    if($sheetDirname !~ /^\s*$/)
    {
	# Read the filenames from the directory given
	$refToExcelFilesList = getExcelFilesFromDir $sheetDirname;
    }
    elsif($sheetFilename !~ /^\s*$/)
    {
	# Read the filenames from the excel file given
	$refToExcelFilesList = getExcelFilesFromFile $sheetFilename;
    }
    elsif($storableFilename  =~ /^\s*$/)
    {
	# nothing to do, just exit function
	return;
    }
    #-----------------------------------------------------------------
    # The main function that parses the information from sheets
    #-----------------------------------------------------------------
    my $refToDefHash;
    if($storableFilename  !~ /^\s*$/)
    {
        # read mem sheets info
	open(STORABLE_IN ,$storableFilename) || die "Unable to open: $storableFilename";
	$refToDefHash = fd_retrieve(\*STORABLE_IN);
	close STORABLE_IN;
    }
    else
    {
	$refToDefHash = readConfig($refToExcelFilesList,$refToExcel);
    }
#For testing to get the generated config printed to terminal
#     $Data::Dumper::Indent = 1;
#     print Dumper($refToDefHash);
#     exit 1;

    #-----------------------------------------------------------------
    # Determinate the default configuration 
    #-----------------------------------------------------------------
    generateConfig($refToResultHash,$refToDefHash,$platId,$platRel,$varName);
    $refToDefHash = undef;

#      #For testing to get the generated config printed to terminal
#      $Data::Dumper::Indent = 1;
#      print Dumper($refToResultHash);
#      exit 1;

}

###################################################
# Actual program
###################################################
my($platId,$platRel,$varName,$sheetDirname,$sheetFilename,$storableFilename,$resultDirname,
   $varNameVariant,$sheetDirnameVariant,$storableFilenameVariant,$sheetFilenameVariant,$formatNbr,
   $addDefCaps,$rfsDir,$noIni) = parseCmdLine;

# ----------------------------------------------------------------  
# Get excel application
# ----------------------------------------------------------------  
my $refToExcel = getExcelApp();

#-----------------------------------------------------------------
# read the default configuration hash
#-----------------------------------------------------------------
my %resultHash;
readSingleConfig($refToExcel,$sheetDirname,$sheetFilename,$storableFilename,\%resultHash,
		 $platId,$platRel,$varName);

#-----------------------------------------------------------------
# read the overriding variant  configuration hash
#-----------------------------------------------------------------
readSingleConfig($refToExcel,$sheetDirnameVariant,$sheetFilenameVariant,$storableFilenameVariant,
		 \%resultHash,$platId,$platRel,$varNameVariant);

#-----------------------------------------------------------------
# quit excel and "delete" the instances.
#-----------------------------------------------------------------
quitExcelApp($refToExcel);

#-----------------------------------------------------------------
# Generate the ini-files
#-----------------------------------------------------------------
if(! $noIni)
{
    generateIniFiles(\%resultHash,$resultDirname,$formatNbr,$addDefCaps);
}

#-----------------------------------------------------------------
# Generate the RFS file (if wanted)
#-----------------------------------------------------------------
if($rfsDir !~ /^\s*$/)
{
    $rfsDir =~ s/[\/\\]$//g;
    $rfsDir .= "/cenrep_rfs.txt";  
    generateRfsFile(\%resultHash,$rfsDir);
}