sysmodellibs/sysmodelgen/src/old/svg/DrawSvg.pm
changeset 6 5b32dc297d05
parent 1 b538b70cbe51
equal deleted inserted replaced
3:e7e0ae78773e 6:5b32dc297d05
       
     1 # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 # Package:      DrawSvg
       
    15 # Build the SVG diagram
       
    16 # 
       
    17 #
       
    18 
       
    19 package DrawSvg;
       
    20 
       
    21 use Cwd;
       
    22 use Cwd 'abs_path';
       
    23 use File::Copy;
       
    24 use File::Path;
       
    25 use FindBin;
       
    26 use lib $FindBin::Bin."/../common";
       
    27 use Getopt::Long qw(:config no_ignore_case);
       
    28 use File::Basename;
       
    29 use File::Spec;
       
    30 
       
    31 
       
    32 use constant KNoCoreOs					=> 0;
       
    33 use constant KCoreOsWithHal			=> 1;
       
    34 use constant KCoreOsWithHardware	=> 2;
       
    35 use constant KOldSystemModelGenerator							=> 202;
       
    36 
       
    37 my @Filters;
       
    38 
       
    39 #-------------------------------------------------------------------------------------------------
       
    40 # Subroutine:   new
       
    41 # Purpose:      
       
    42 # Input:        None (extracted from command line args)
       
    43 # Output:       A reference to itself
       
    44 #-------------------------------------------------------------------------------------------------
       
    45 sub new
       
    46 	{
       
    47     my $package = shift;
       
    48     my $self = {};              # Create reference to object
       
    49     bless $self,  $package;    # Associate a reference with class name
       
    50     
       
    51     $self->{iScriptCode} = 999;
       
    52     
       
    53     # basic test of command line:
       
    54     if (scalar(@ARGV) == 0)
       
    55     	{
       
    56 		$self->Help();
       
    57         exit Logger::KErrorNone;	# nothing to do. Leave
       
    58     	}
       
    59     
       
    60     # process the input:
       
    61     $self->ParseCommandLineOptions();
       
    62     
       
    63     $self->{iReturnCode} = Logger::KErrorNone;
       
    64     return $self;
       
    65 	}
       
    66 
       
    67 
       
    68 # gets the schema versions without comsuming any of the command line arguments
       
    69 sub SchemaVersionsFromArgs
       
    70 	{ 
       
    71 	my @sysdefs;
       
    72 	my @ini;
       
    73 	my $model;
       
    74 	for(my $i=0;$i<=$#_;$i++)
       
    75 		{
       
    76 		if($_[$i] eq '-model')
       
    77 			{
       
    78 			$model=$_[++$i];
       
    79 			}
       
    80 		if($_[$i] eq '-sysdef')
       
    81 			{
       
    82 			$i++;
       
    83 			push(@sysdefs,split(/,/,$_[$i]));
       
    84 			}
       
    85 		elsif($_[$i] eq '-i')
       
    86 			{
       
    87 			push(@ini,$_[++$i]);
       
    88 			}
       
    89 		}
       
    90 	if(!scalar(@sysdefs) )
       
    91 		{
       
    92 		foreach my $in (@ini)
       
    93 			{
       
    94 			open(INI,$in);
       
    95 			my $iniDir = $in;
       
    96 			$iniDir =~ s,[^\\//]+$,,;
       
    97 			while(my $line = <INI>)
       
    98 				{
       
    99 				$line =~ s/^\s*//; 		# remove spaces
       
   100 				$line =~ s/\s*$//;		# a/a
       
   101 				$line =~ s/\n$//; 		# remove new line
       
   102 				if($line =~/"/) {
       
   103 					$line =~ s/^(([^"#]*"[^"]*")+)#.*$/$1/; 		# remove comments indicated by # (to the end of the line)
       
   104 				}  else {
       
   105 					$line =~ s/#.*$//; 		# remove comments indicated by # (to the end of the line)
       
   106 				}
       
   107 				next if $line eq ""; 	# ignore blank lines
       
   108 				if ($line =~ m/sysdef\s*=\s*(.*)/i)
       
   109 					{
       
   110 					foreach my $file (split(/,/,$1))
       
   111 						{
       
   112 						push(@sysdefs,&FullPath($iniDir,$file));
       
   113 						}
       
   114 					}
       
   115 				}
       
   116 			close INI;
       
   117 			}
       
   118 		}
       
   119 	my $dir = $model;
       
   120 	$dir=~s,[^/\\]+$,,;
       
   121 	open M,$model;
       
   122 	$/=">";
       
   123 	while(my $line=<M>)
       
   124 		{
       
   125 		if($line=~s/<sysdef.*href=("[^"]+"|'[^']+')//)
       
   126 			{
       
   127 			my $f=$1;
       
   128 			$f=~s/^.(.*).$/$1/;
       
   129 			if(! ($f=~/^(\/|[a-z]+:)/)) {$f="$dir$f"}
       
   130 			push(@sysdefs,$f);
       
   131 			}
       
   132 		}
       
   133 	close M;
       
   134 	my %res;
       
   135 	foreach my $file (@sysdefs)
       
   136 		{
       
   137 		open S,$file;
       
   138 		while(my $line = <S>)
       
   139 			{
       
   140 			if($line =~ /<SystemDefinition.*\sschema="(.*?)"/s)
       
   141 				{
       
   142 				push(@{$res{$1}},$file);
       
   143 				last;
       
   144 				}
       
   145 			}
       
   146 		close S;
       
   147 		}
       
   148 	$/="\n";
       
   149 	return %res;
       
   150 	}
       
   151 
       
   152 sub GuessReleaseNumber()
       
   153 	{
       
   154 	my $self = shift;	
       
   155 	# always use release value if defined
       
   156 	$self->{iRelease} && return $self->{iRelease} ;
       
   157 	# if not there, it's in the s12,
       
   158 	my $ver;
       
   159 	my $t = $/;
       
   160 	foreach my $s12 (@{$self->{'iS12'}})		# use version from first s12 file listed
       
   161 		{
       
   162 		if(-d $s12) {next}
       
   163 		open(FILE,$s12) || return;
       
   164 		$/='>';
       
   165 		while(<FILE>)
       
   166 			{
       
   167 			if(/<Schedule12\s.*\bOS_version=('(.*?)'|"(.*?)")/s)
       
   168 				{
       
   169 				$ver = $2 || $3;
       
   170 				last;
       
   171 				}
       
   172 			}
       
   173 		close FILE;
       
   174 		$/=$t;
       
   175 		return  $ver;
       
   176 		}
       
   177 	# not there either, 
       
   178 	if($self->{'iDepsFile'}) 
       
   179 		{
       
   180 		open(FILE,$self->{'iDepsFile'}) || return;
       
   181 		$/='>';
       
   182 		while(<FILE>)
       
   183 			{
       
   184 			if(/<SystemModelDeps\s.*\bversion=('(.*?)'|"(.*?)")/s)
       
   185 				{
       
   186 				$ver = $2 || $3;
       
   187 				last;
       
   188 				}
       
   189 			}
       
   190 		close FILE;
       
   191 		$/=$t;
       
   192 		return  $ver;
       
   193 		}
       
   194 	return "";
       
   195 	}
       
   196 
       
   197 
       
   198 # an empty value indicates its a single file. Any other value means it's a list separated by that value as a regexp
       
   199 %KFileParams = 
       
   200 	( 
       
   201 	'iSysDefFile'	=> ',',
       
   202 	'iS12'		=> ',',
       
   203 	'iExtra'		=> ',',
       
   204 	'iDepsFile'	=> '',
       
   205 	'iLocalize'		=> ',',
       
   206 	'iLevels'		=> ',',
       
   207 	'iStyle'		=> ',',
       
   208 	'iOverlay'		=> ',',
       
   209 	'iBorder'		=> ',',
       
   210 	'iColor'		=> ',',
       
   211 	'iShapes'		=> '',
       
   212 	'iLogoSrc'		=> '',
       
   213 	'iModel'		=> '',
       
   214 	'iLogFile'		=> '',
       
   215 	);
       
   216 
       
   217 sub ParseCommandLineOptions()
       
   218 	{
       
   219 	my $self = shift;
       
   220 	
       
   221 	# Possible arguments (with default values where possible):
       
   222 	my $help;
       
   223 	$self->{iSysDefFile};
       
   224 	$self->{iDepsFile};
       
   225 	$self->{iOutputCsv};
       
   226 	$self->{iCsvColumns};
       
   227 	$self->{iCsvLabels};
       
   228 	$self->{iTemporaryDirectory};
       
   229 	$self->{iLogFile};
       
   230 	$self->{iWarningLevel};
       
   231 	$self->{iClean}; # if specified, it will delete the temp directory.
       
   232 
       
   233 	# custom properties:
       
   234 	$self->{iDiagram}; # the output svg
       
   235 	$self->{iCopyright};
       
   236 	$self->{iRelease};
       
   237 	$self->{iName};
       
   238 	$self->{iLabel};
       
   239 	$self->{iModel};
       
   240 	$self->{iCoreOs};
       
   241 	$self->{iLevels};
       
   242 	$self->{iExtra};
       
   243 	$self->{iIniFile};
       
   244 	$self->{iS12};
       
   245 	$self->{iLink};
       
   246 	# Read in the user arguments:
       
   247 	GetOptions( "h"						=> \$help,
       
   248 				"i=s"					=> \$self->{iIniFile},
       
   249 				"output=s"				=> \$self->{iDiagram} ,
       
   250 				"csv_output=s"				=> \$self->{iOutputCsv} ,
       
   251 				"csv_columns=s"				=> \$self->{iCsvColumns} ,
       
   252 				"csv_labels=s"				=> \$self->{iCsvLabels} ,
       
   253 				'xml_output=s'				=> \$self->{iOutputXml} ,
       
   254 				"model=s"				=> \$self->{iModel} ,
       
   255 				"sysdef=s"				=> \@{$self->{iSysDefFile}} ,
       
   256 				"srcvar=s"				=> \@{$self->{iSourceRoot}} ,
       
   257 				"shapes=s"				=> \$self->{iShapes},
       
   258 				"link=s"				=> \$self->{iLink},
       
   259 				"system_name=s"			=> \$self->{iName} ,
       
   260 				"system_version=s"		=> \$self->{iRelease} ,
       
   261 				"model_name=s"			=> \$self->{iLabel} ,
       
   262 				"model_version=s"		=> \$self->{iRevision},
       
   263 				"model_version_type=s"	=> \$self->{iRevisionType},
       
   264 				"copyright=s"			=> \$self->{iCopyright},
       
   265 				"distribution=s"		=> \$self->{iDistribution},
       
   266 				"legend_title=s"		=> \$self->{iLgdTitle},
       
   267 				"coreos=s"				=> \$self->{iCoreOs},
       
   268 				
       
   269 				"sysinfo=s"				=> \@{$self->{iExtra}},
       
   270 				"localize=s"			=> \@{$self->{iLocalize}},
       
   271 				"levels=s"				=> \@{$self->{iLevels}},
       
   272 				
       
   273 				"color=s"				=> \@{$self->{iColor}},
       
   274 				"border-shape=s"		=> \@{$self->{iBorder}},
       
   275 				"pattern=s"				=> \@{$self->{iOverlay}},
       
   276 				"border-style=s"		=> \@{$self->{iStyle}},
       
   277 				
       
   278 				"filter=s"				=> \@{$self->{iFilter}},
       
   279 				"filter-has=s"				=> \&OrderedOption,
       
   280 				"show-attr=s"			=> \&OrderedOption,
       
   281 				"hide-attr=s"			=> \&OrderedOption,
       
   282 				"ignore=s"				=> \@{$self->{iIgnore}},
       
   283 				
       
   284 				"s12=s"				=>  \@{$self->{iS12}},
       
   285 				
       
   286 				"detail=s"				=> \$self->{iDetail},
       
   287 				"detail-type=s"				=> \$self->{iDetailType},
       
   288 				"page-width=s"			=> \$self->{iPageWidth},
       
   289 				"static"				=> \$self->{iStatic},
       
   290 				"deps=s"				=> \$self->{iDepsFile},
       
   291 				"w=s"					=> \$self->{iWarningLevel},
       
   292 				"clean"				=> \$self->{iClean},				
       
   293 				"compress"				=> \$self->{iCompress},
       
   294 				"tempdir=s"				=> \$self->{iTemporaryDirectory},
       
   295 				"dpi=s"				=> \$self->{iPrintResolution},
       
   296 				"model_font=s"				=> \$self->{iModelFont},
       
   297 				"version-list=s"			=>  \$self->{iVersions},
       
   298 				"log=s"				=> \$self->{iLogFile},
       
   299 				"logo=s"				=> \$self->{iLogoSrc},
       
   300 				"logo-height=s"				=> \$self->{iLogoHeight},
       
   301 				"logo-width=s"				=> \$self->{iLogoWidth},
       
   302 				"legend-width=s"			=> \$self->{iLegendWidth},
       
   303 				"legend-max-scale=s"			=> \$self->{iLegendMaxScale},
       
   304 				"title-scale=s"			=> \$self->{iTitleScale},
       
   305 				"xslt-param=s"			=> \%{$self->{iXsltParam}},
       
   306 				"note=s"			=> \@{$self->{iLegendNote}}
       
   307 				);
       
   308 
       
   309 	if ($help)
       
   310 	    {
       
   311 	   	warn $self->Help();
       
   312 	   	exit Logger::KErrorNone;
       
   313 	   	}
       
   314 
       
   315 	@{$self->{'iFiltering'}} = @Filters;
       
   316 	@Filters=();
       
   317 	my $i=0;
       
   318 	for($i=0;$i<=$#ARGV;$i++)
       
   319 		{ # check remaining args to ensure they are valid
       
   320 			if($ARGV[$i]=~/^(http|file):\/\//) { # assume URLs are correct
       
   321 				next;			
       
   322 				}
       
   323 			if($ARGV[$i] eq "-" || $ARGV[$i] eq "") 
       
   324 				{ #special values to use nothing or use the tmp file, but only valid for odd numbered args
       
   325 				if($i%2==1) {next}
       
   326 				$self->Help();
       
   327 				&Logger::LogFatal("Invalid syntax", KOldSystemModelGenerator, 0,Logger::KIncorrectSyntax);
       
   328 				}
       
   329 			if(!(-e $ARGV[$i])) {
       
   330 				warn "file $ARGV[$i] does not exist";
       
   331 	   			exit Logger::KFileDoesNotExist;
       
   332 			}
       
   333 		}
       
   334 	
       
   335 	# Now read the ini file and override command line if necessary:
       
   336 	my @yr = gmtime();
       
   337 	my $dataroot =&SystemModelXmlDataDir();
       
   338 	my %defaults = (
       
   339 		'iCopyright' 			=> (1900+$yr[5])." Nokia Corporation",
       
   340 		'iDiagram' 			=> "sysmodel.svg",
       
   341 		'iTemporaryDirectory' 	=> "drawsvg_temp",
       
   342 		'iName' 				=> "Symbian OS"	,
       
   343 		'iLabel' 				=> "System Model",
       
   344 		'iLgdTitle' 				=> "Key",
       
   345 		'iShapes' 				=> "$dataroot/Shapes.xml" 	,
       
   346 		'iLogFile' 				=> ""  # do not set this to any default: stdout is used if log file isn't set
       
   347 	);
       
   348 	my %defaultsForMulti = (
       
   349 		'iLocalize' 			=> "$dataroot/display-names.xml" ,
       
   350 		'iExtra' 				=> "$dataroot/SystemInfo.xml"   
       
   351 	);
       
   352 
       
   353 	$self->ReadIniFile();
       
   354 
       
   355 	foreach my $type ('iSysDefFile', 'iFilter','iSourceRoot')
       
   356 		{
       
   357 		if(scalar(@{$self->{$type}})==1 && $self->{$type}->[0]=~/,/)
       
   358 			{ # treat as comma-separated for backwards compatibility (leave alone if no commas)
       
   359 			@{$self->{$type}} = split(/,/,$self->{$type}->[0]);
       
   360 			}
       
   361 		}
       
   362 	if (scalar(@{$self->{iIgnore}})) 
       
   363 		{
       
   364 		foreach my $type ('iIgnore')
       
   365 			{
       
   366 			if(scalar(@{$self->{$type}})==1)
       
   367 				{ # treat as semicolon-separated for backwards compatibility
       
   368 				@{$self->{$type}} = split(/;/,$self->{$type}->[0]);
       
   369 				}
       
   370 			}
       
   371 		}
       
   372 	else
       
   373 		{
       
   374 		push(@{$self->{iIgnore}}, "layer:Tools and Utils and SDKENG","layer:MISC","block:Techview") 
       
   375 		}
       
   376 
       
   377 	
       
   378 	my $ver = $self->GuessReleaseNumber(); # determine release from attached files.
       
   379 		
       
   380 	# Use a special levels.xml file for 9.1 (unless it's specified by the user):
       
   381 	push(@{$self->{iLevels}}, "$dataroot/Levels91.xml") if !scalar(@{$self->{iLevels}}) and $ver eq "9.1";
       
   382 	push(@{$self->{iLevels}}, "$dataroot/Levels.xml") if !scalar(@{$self->{iLevels}}) and ($ver eq "9.2" or $ver eq "9.2" );
       
   383 
       
   384 	if(!scalar(@{$self->{'iFiltering'}}) && !scalar(@{$self->{'iFilter'}}))
       
   385 		{ # filter only has a default if fitler-has is not set
       
   386 		@{$self->{'iFilter'}}= ("java","gt");
       
   387 		}
       
   388 	while (($key, $value) = each %defaults) {
       
   389 		$self->{$key} = $value if ! defined $self->{$key};
       
   390 	}
       
   391 
       
   392 	while (($key, $value) = each %defaultsForMulti) {
       
   393 		push(@{$self->{$key}}, $value) if ! scalar(@{$self->{$key}});
       
   394 	}
       
   395 
       
   396 
       
   397 
       
   398 	# if saving to .svgz, try to compress
       
   399 	$self->{iCompress} = $self->{iCompress} || ( $self->{iDiagram} =~ /\.svgz$/i );
       
   400 
       
   401 	# if there's a deps file XSLT will get revision number and type from that.
       
   402 	# if there is no deps file and neither revision nor revision type are specified, default to "DRAFT 1"
       
   403 	if(!$self->{'iDepsFile'} &&  !$self->{'iRevision'} && !$self->{'iRevisionType'})
       
   404 		{
       
   405 		$self->{'iRevisionType'} = "draft";
       
   406 		$self->{'iRevision'} = "1";
       
   407 		}
       
   408 	
       
   409 	if ($self->{iShapes} eq "$dataroot/Shapes.xml"  && !scalar(@{$self->{'iColor'}}))
       
   410 		{ # if it's got the default shapes use default colours
       
   411 		@{$self->{iColor}} = (&SystemModelColorsXmlFile());
       
   412 		}
       
   413 
       
   414 	if(defined $self->{iCoreOs})
       
   415 		{
       
   416 		if($self->{iCoreOs}=~/(on|yes|true)$/i )
       
   417 			{
       
   418 			$self->{iCoreOs} = KCoreOsWithHal;
       
   419 			}
       
   420 		elsif($self->{iCoreOs}=~/(off|no|false)$/i )
       
   421 			{
       
   422 			$self->{iCoreOs} = KNoCoreOs;
       
   423 			}
       
   424 		elsif(! ($self->{iCoreOs}=~/^[0-9]+$/ ))	# any other non-number
       
   425 			{
       
   426 			$self->{iCoreOs} = KCoreOsWithHardware;
       
   427 			}
       
   428 		}
       
   429 	else		# use version numebr to decide
       
   430 		{
       
   431 		$self->{iCoreOs} = ($self->{iRelease} eq 'Future' || $ver > 9.4) ? KCoreOsWithHardware :
       
   432 			(($ver=~/^9\.4/) ? KCoreOsWithHal : KNoCoreOs);
       
   433 	}
       
   434 
       
   435 	$self->{'iGuessVer'} = $ver;
       
   436 
       
   437 	mkpath $self->{iTemporaryDirectory} if ! -d $self->{iTemporaryDirectory};
       
   438 
       
   439 	# set the log file if needed:
       
   440 	$Logger::LOGFILE = $self->{iLogFile} if $self->{iLogFile};
       
   441 	
       
   442 	# set the correct warning level:
       
   443 	#  -w=1: errors only (default)
       
   444 	#  -w=2: warnings as well as errors
       
   445 	#  -w=3: info messages, warnings and errors.
       
   446 	if (defined $self->{iWarningLevel} and $self->{iWarningLevel} > 1)
       
   447 		{
       
   448 		if ($self->{iWarningLevel} == 2)
       
   449 			{
       
   450 			$self->{iWarningLevel} = LogItem::WARNING;
       
   451 			}
       
   452 		elsif ($self->{iWarningLevel} == 3)
       
   453 			{
       
   454 			$self->{iWarningLevel} = LogItem::INFO;
       
   455 			}
       
   456 		else # for anything higher than set it to LogItem::VERBOSE
       
   457 			{
       
   458 			$self->{iWarningLevel} = LogItem::VERBOSE;
       
   459 			}
       
   460 		}
       
   461 	else
       
   462 		{
       
   463 		$self->{iWarningLevel} = LogItem::ERROR;
       
   464 		}
       
   465 	# set the logger up:
       
   466 	$Logger::SEVERITY = $self->{iWarningLevel};
       
   467 	
       
   468 	# set all URIs
       
   469 
       
   470 	(my $dir  = cwd ) =~ s#\/#\\#g;
       
   471 	
       
   472 	
       
   473 	foreach ( keys(%KFileParams)) {
       
   474 		if($self->{$_} eq '') {next} # no value, so do nothing
       
   475 		if($KFileParams{$_} eq '') {
       
   476 			$self->{$_}  = &FullPath("$dir\\",	$self->{$_} );
       
   477 		} elsif($KFileParams{$_} eq ',') {
       
   478 			foreach my $item  (@{$self->{$_}})	{
       
   479 				if ($item eq '') {next}	# skip if explicitly set to empty
       
   480 				$item = &FileAsUrl(&FullPath("$dir\\",$item));
       
   481 			}
       
   482 			next;
       
   483 		} 
       
   484 		$self->{$_} = &FileAsUrl($self->{$_});
       
   485 	}	
       
   486 
       
   487 }
       
   488 
       
   489 
       
   490 sub OrderedOption() {
       
   491 	my $var = shift;
       
   492 	my $val = shift;
       
   493 	if($var=~/^(show|hide)-attr$/) {
       
   494 		my $f = "<filter display='$1' ";
       
   495 		if($val=~s/^([^=]+)=//) {$f.="select='$1' value='$val'/>"}
       
   496 		else {$f.="select='$val'/>"}
       
   497 		push(@Filters,$f);
       
   498 	} elsif($var eq 'filter-has' && $val eq '*') {
       
   499 		push(@Filters,"<filter display='show' select='*'/>");
       
   500 	}elsif($var eq 'filter-has') {
       
   501 		if(!scalar(@Filters)) { # if the 1st is showing a filter than that implies everythig without a filter is turned off 
       
   502 			push(@Filters,'<filter select="*" display="hide"/>');
       
   503 		}
       
   504 		foreach my $v (split(/,/,$val)) {
       
   505 			push(@Filters,"<filter display='show' select='filter' value='$v'/>");
       
   506 		}
       
   507 	}
       
   508 }
       
   509 
       
   510 
       
   511 
       
   512 sub FullPath {
       
   513 	my $root = shift;
       
   514 	my $file = shift;
       
   515 	
       
   516 	# If the file is not specified then return null
       
   517 	if (!$file) {
       
   518 		return;
       
   519 	}
       
   520 	
       
   521 	
       
   522 	# If the file is a URL or Windows path then return it as is
       
   523 	if ($file =~ /:/) {
       
   524 		return $file;
       
   525 	}
       
   526 	
       
   527 	if ($root && !-e $root) {
       
   528 		&Logger::LogFatal("root $root does not exist");
       
   529 	}
       
   530 	
       
   531 	if (-f $root) {
       
   532 		$root = File::Basename::dirname($root)
       
   533 	}
       
   534 
       
   535 	# if root is empty or the same dir, then file is relative
       
   536 	if($root eq '' or $root eq '.') {
       
   537 		return $file;
       
   538 	}	
       
   539 	
       
   540 	# If the file is relative from the root then we want to add the drive letter to the file (if one exists)
       
   541 	if ($file =~ s/^[\\\/]// ) {
       
   542 		if ($root =~ /^([a-z]:)/i) {
       
   543 			return File::Spec->catdir($1, $file);
       
   544 		}
       
   545 	}
       
   546 	
       
   547 	# Return the concatenated root and filename
       
   548 	return File::Spec->catdir($root, $file);
       
   549 }
       
   550 
       
   551 
       
   552 sub ReadIniFile()
       
   553 	{
       
   554 	my $self = shift;
       
   555 	
       
   556 	return if ! defined $self->{iIniFile};
       
   557 	
       
   558 	# Log a fatal error if the ini file is defined but doesn't exist:
       
   559 	&Logger::LogFatal("ini file does not exist\"$self->{iIniFile}\": $!", KOldSystemModelGenerator) if ! -e $self->{iIniFile};
       
   560 	
       
   561 	open(INI, $self->{iIniFile}) or 	
       
   562 		&Logger::LogFatal("Could not open the ini file \"$self->{iIniFile}\": $!", KOldSystemModelGenerator);
       
   563 	
       
   564 	&Logger::LogInfo("Reading ini file \"$self->{iIniFile}...", KOldSystemModelGenerator);
       
   565 	
       
   566 	%AllowMulitples = (
       
   567 		"iLocalize"		=> 1,
       
   568 		"iExtra"		=> 1,
       
   569 		'iLevels'		=> 1,
       
   570 		'iSysDefFile'		=> 1,
       
   571 		'iSourceRoot'		=> 1,
       
   572 		'iS12'		=> 1,
       
   573 		"iIgnore"		=> 1,
       
   574 		"iFilter"		=> 1,
       
   575 		"iStyle"		=> 1,
       
   576 		"iOverlay"		=> 1,
       
   577 		"iBorder"		=> 1,
       
   578 		"iColor"		=> 1,
       
   579 		"iLegendNote" => 1,
       
   580 		"iXsltParam" => 2
       
   581 	); # value of 2 means it's a hash, value of 1 is an array
       
   582 	
       
   583 	foreach my $m (keys %AllowMulitples) {
       
   584 		# if it's already set, note that we're to ignore anything in the ini file
       
   585 		if($AllowMulitples{$m}==2 ? (scalar(%{$self->{$m}})>0) : (scalar(@{$self->{$m}})>0)) {$AllowMulitples{$m}=0}
       
   586 	}
       
   587 	
       
   588 	%Ordered = (
       
   589 		"filter-has"				=> 1,	
       
   590 		"show-attr"			=> 1,
       
   591 		"hide-attr"			=> 1
       
   592 	);
       
   593 
       
   594 	%IniMap = (
       
   595 		"model"					=> 'iModel' ,
       
   596 		"sysdef"				=> 'iSysDefFile' ,
       
   597 		'srcvar'					=> 'iSourceRoot',
       
   598 		"shapes"				=> 'iShapes',
       
   599 		"system_name"			=> 'iName' ,
       
   600 		"model_name"			=> 'iLabel' ,
       
   601 		"system_version"		=> 'iRelease' ,
       
   602 		"copyright"				=> 'iCopyright',
       
   603 		"model_version"			=> 'iRevision',
       
   604 		"model_version_type"	=> 'iRevisionType',
       
   605 		"distribution"			=> 'iDistribution',
       
   606 		"legend_title"			=> 'iLgdTitle',
       
   607 		"coreos"				=> 'iCoreOs',
       
   608 		"sysinfo"				=> 'iExtra',
       
   609 		"localize"				=> 'iLocalize',
       
   610 		"levels"				=> 'iLevels',
       
   611 		"filter"				=> 'iFilter',
       
   612 		"ignore"				=> 'iIgnore',
       
   613 		"output"				=> 'iDiagram',
       
   614 		"csv_output"				=> 'iOutputCsv',
       
   615 		"csv_columns"				=> 'iCsvColumns' ,
       
   616 		"csv_labels"				=> 'iCsvLabels' ,
       
   617 		'xml_output'				=> 'iOutputXml' ,
       
   618 		"detail"				=> 'iDetail',
       
   619 		"detail-type"				=> 'iDetailType',
       
   620 		"page-width"			=> 'iPageWidth',
       
   621 		"static"				=> 'iStatic',
       
   622 		"color"					=> 'iColor',
       
   623 		"border-shape"			=> 'iBorder',
       
   624 		"pattern"				=> 'iOverlay',
       
   625 		"deps"					=> 'iDepsFile',
       
   626 		"border-style"			=> 'iStyle',
       
   627 		"w"						=> 'iWarningLevel',
       
   628 		"tempdir"				=> 'iTemporaryDirectory',
       
   629 		'dpi'					=>'iPrintResolution',
       
   630 		'model_font'					=>'iModelFont',
       
   631 		"s12"				=> 'iS12',
       
   632 		"log"					=> 'iLogFile',
       
   633 		"logo"				=> 'iLogoSrc',
       
   634 		"logo-height"			=> 'iLogoHeight',
       
   635 		"logo-width"			=> 'iLogoWidth',
       
   636 		'version-list'			 => 'iVersions',
       
   637 		"link"					=> 'iLink',
       
   638 		"clean"				=> 'iClean',
       
   639 		"compress"			=> 'iCompress',
       
   640 		"legend-width"			=>'iLegendWidth',
       
   641 		"legend-max-scale"		=> 'iLegendMaxScale',
       
   642 		"title-scale"			=> 'iTitleScale',
       
   643 		"xslt-param"			=> 'iXsltParam',
       
   644 		"note"			=> 'iLegendNote'
       
   645 	);
       
   646 	
       
   647 	foreach my $line (<INI>)
       
   648 		{
       
   649 		$line =~ s/^\s*//; 		# remove spaces
       
   650 		$line =~ s/\s*$//;		# a/a
       
   651 		$line =~ s/\n$//; 		# remove new line
       
   652 		if($line =~/"/) {
       
   653 			$line =~ s/^(([^"#]*"[^"]*")+)#.*$/$1/; 		# remove comments indicated by # (to the end of the line)
       
   654 		}  else {
       
   655 			$line =~ s/#.*$//; 		# remove comments indicated by # (to the end of the line)
       
   656 		}
       
   657 		next if $line eq ""; 	# ignore blank lines
       
   658 		if ($line =~ m/([^=]+)\s*=\s*(.*)/)
       
   659 			{
       
   660 			my $argType = lc $1; 	# case-insensitive
       
   661 			my $argValue = $2; 		# case-sensitive as it can have strings intended for html output
       
   662 			
       
   663 			$argType =~ s/^\s*//; # remove spaces on either end (Cannot use s/\s+// as this will not be suitable for html text)
       
   664 			$argType =~ s/\s*$//;
       
   665 			$argValue =~ s/^\s*//;
       
   666 			$argValue =~ s/\s*$//;
       
   667 			
       
   668 			$argValue =~ s/^'//; # no need for quotes around the values
       
   669 			$argValue =~ s/'$//;
       
   670 			$argValue =~ s/^"//;
       
   671 			$argValue =~ s/"$//;
       
   672 
       
   673 			my $iniDir = $self->{iIniFile};
       
   674 			$iniDir =~ s,[^\\//]+$,,;
       
   675 			#$iniDir .= '\\';
       
   676 
       
   677 			if(defined $Ordered{$argType}) {
       
   678 				&OrderedOption($argType, $argValue);
       
   679 			} elsif(defined $IniMap{$argType}) {
       
   680 				my $param = $IniMap{$argType};
       
   681 				# make sure all files mentioned are taken relative to the ini file
       
   682 				if($KFileParams{$param} ne '' )
       
   683 					{# comma-separated filenames
       
   684 					my @list;
       
   685 					foreach my $item  (split(/,/,$argValue))
       
   686 						{
       
   687 						push(@list,&FullPath($iniDir,$item));
       
   688 						}
       
   689 					$argValue = join(',',@list);
       
   690 					}
       
   691 				elsif(defined $KFileParams{$param} && $argValue ne '')
       
   692 					{# single file names			
       
   693 					$argValue = &FullPath($iniDir,$argValue);
       
   694 					}
       
   695 				# do not override! Only set values that have not been set on command line already
       
   696 				if ($AllowMulitples{$param}==1)  # check so we don't add if it's set by the cmd line
       
   697 					{
       
   698 				 	push(@{$self->{$param}}, $argValue); 
       
   699 					} 
       
   700 				elsif ($AllowMulitples{$param}==2)  # check so we don't add if it's set by the cmd line
       
   701 					{
       
   702 					$argValue=~s/^([^=]+)=//;
       
   703 				 	$self->{$param}->{$1}=$argValue; 
       
   704 					} 
       
   705 				elsif (! defined $AllowMulitples{$param})
       
   706 					{
       
   707 				 	$self->{$param} = $argValue if ! $self->{$param}; 
       
   708 					}
       
   709 				}
       
   710 			}
       
   711 		}
       
   712 ; 
       
   713 	@{$self->{'iFiltering'}} = @Filters if ! @{$self->{'iFiltering'}}; 
       
   714 	@Filters=();
       
   715 	}
       
   716 
       
   717 sub MakeInfo() {
       
   718 	my $self = shift;
       
   719 	my %files = @_;
       
   720 	my $res="";
       
   721 	while (my ($key,$value) = each %files) {
       
   722 		 if ($self->{$key} ne '') {
       
   723 		 	$res .= "\t\t<info href='".$self->{$key}."' type='$value'/>\n"
       
   724 		 }
       
   725 	}
       
   726 	return $res;
       
   727 }
       
   728 
       
   729 sub MakeMultiInfo() {
       
   730 	my $self = shift;
       
   731 	my %files = @_;
       
   732 	my $res="";
       
   733 	while (my ($key,$value) = each %files) {
       
   734 		 foreach my $m (@{$self->{$key}}) {
       
   735 		 	if($m ne '') { # skip if empty
       
   736 		 		$res .= "\t\t<info href='$m' type='$value'/>\n"
       
   737 		 	}
       
   738 		 }
       
   739 	}
       
   740 	return $res;
       
   741 }
       
   742 
       
   743 sub MakeAttirbutes() {
       
   744 	my $self = shift;
       
   745 	my %atts = @_;
       
   746 	my $res="";
       
   747 	while (my ($key,$value) = each %atts) {
       
   748 		 if (defined $self->{$key}) {
       
   749 		 	my $cur = $self->{$key};
       
   750 		 	if($key=~/File$/) {$cur=&FileAsUrl($cur)}	# anything that ends in File is treated as a URL
       
   751 		 	$res .= " $value=\"$cur\"";
       
   752 		 }
       
   753 	}
       
   754 	return $res;
       
   755 }
       
   756 
       
   757 sub getSchedule12Xml ()
       
   758 	{
       
   759 	my $self = shift;
       
   760 	my $ver = shift;
       
   761 	my @files = @{$self->{'iS12'}};
       
   762 	my @ret;
       
   763 	foreach my $s12 (@files)
       
   764 		{
       
   765 		if($s12 eq '') {next}
       
   766 		if($s12=~/^file:\/\/\/(.*)$/)
       
   767 			{
       
   768 			if(-d $1) 
       
   769 				{
       
   770 				# it's a directory, so append Symbian_OS_v[version]_Schedule12.xml
       
   771 				$s12=~s,[\\/]*$,/Symbian_OS_v${ver}_Schedule12.xml,;
       
   772 				}
       
   773 			}
       
   774 		push(@ret,$s12);
       
   775 		}
       
   776 	return @ret
       
   777 	}	
       
   778 
       
   779 sub getModel()
       
   780 	{
       
   781 	my $self = shift;
       
   782 	if($self->{iModel})  {return $self->{iModel}}
       
   783 	
       
   784 	my $xsltDir = $self->GetXsltDir();
       
   785 
       
   786 	my $tempDirectoryPathname = abs_path($self->{iTemporaryDirectory});
       
   787 	
       
   788 	(my $modelXml = "$tempDirectoryPathname/Model.xml") =~ s#\/#\\#g;
       
   789 	(my $modelTemplateXml = $xsltDir."/") =~ s#\/#\\#g;
       
   790 	
       
   791 	if($self->{iCoreOs} == KCoreOsWithHardware)	{ #  show 9.5+ CoreOS 
       
   792 		$modelTemplateXml .= "ModelTemplate.xml";
       
   793 	} elsif($self->{iCoreOs} == KCoreOsWithHal )  	{ 		# show 9.4 CoreOS
       
   794 		$modelTemplateXml .= "ModelTemplate.mid.xml";
       
   795 	} else {
       
   796 		$modelTemplateXml .= "ModelTemplate.older.xml";
       
   797 	}
       
   798 
       
   799 
       
   800 	# the follownig params cannot be emtpy, delete if they are
       
   801 	foreach my $item ('iCopyright' ,	'iDistribution' ,'iDepsFile',	'iLink', 'iDetailType',  'iDetail', 'iVersions')
       
   802 		{
       
   803 		if($self->{$item} eq '') {delete $self->{$item}}
       
   804 		}
       
   805 
       
   806 
       
   807 	# Step 1:
       
   808 	# Create a Model.xml based on the ModelTemplate.xml
       
   809 	open (INPUT, $modelTemplateXml) or &Logger::LogError("Xalan error ($?) occured in Step 1 of SVG building (<$modelTemplateXml)...", KOldSystemModelGenerator, 1);
       
   810 	open (OUTPUT, ">$modelXml") or &Logger::LogError("Xalan error ($?) occured in Step 1 of SVG building (>$modelXml)...", KOldSystemModelGenerator, 1);
       
   811 	my $release = $self->{iRelease};
       
   812 	
       
   813 	
       
   814 	# Since $self->{iSysDefFile} may be a comma-separated list of sysdefs, create a <sysdef> tag for each one of the files:
       
   815 	my $sysdefTagsForModelTemplate = "";	
       
   816 
       
   817 	@{$self->{'iS12'}} = $self->getSchedule12Xml($self->{'iGuessVer'});
       
   818 
       
   819 	if(scalar(@{$self->{iSourceRoot}}) == 1)
       
   820 		{
       
   821 		@{$self->{iSourceRoot}} = ($self->{iSourceRoot}->[0]) x scalar($self->{iSourceRoot}->[0]);
       
   822 		}
       
   823 	
       
   824 	for (my $index = 0; $index < scalar(@{$self->{iSysDefFile}}); ++$index)
       
   825 		{
       
   826 		$sysdefTagsForModelTemplate .= $self->CreateSysDefTagsForModelXML($self->{iSysDefFile}->[$index], $self->{iSourceRoot}->[$index]);
       
   827 		}
       
   828 	
       
   829 	my $display;
       
   830 
       
   831 	if($self->{iLink}=~/\\/)    # it's a windows dir, change to file URI
       
   832 		{
       
   833 		$self->{iLink} = &FileAsUrl($self->{iLink});
       
   834 		}
       
   835 
       
   836 	$display .= $self->MakeMultiInfo ('iLocalize' 	=> 'abbrev');
       
   837 
       
   838 	my %infoMap = (
       
   839 		'iStyle'  		=> 'style',
       
   840 		'iOverlay'		=> 'overlay',
       
   841 		 'iBorder'		=> 'border',
       
   842 		 'iColor'		=> 'color'		
       
   843 	);
       
   844 	
       
   845 	$display .=$self->MakeMultiInfo( %infoMap);
       
   846 	if($self->{'iLogoSrc'})
       
   847 		{
       
   848 		$display.="\n<logo". $self->MakeAttirbutes(
       
   849 			'iLogoSrc' 	=> 'src',
       
   850 			'iLogoWidth'  		=> 'width',
       
   851 			'iLogoHeight'  		=> 'height'
       
   852 			) ;
       
   853 		if($self->{'iLogoSrc'} =~ /\.svg$/i)
       
   854 			{
       
   855 			$display.= " embed=\"yes\"";
       
   856 			}
       
   857 		$display.= "/>";
       
   858 		}
       
   859 
       
   860 	my $filters='';
       
   861 	if(scalar @{$self->{'iFiltering'}})	# complex filtering 
       
   862 		{
       
   863 		$filters = join("\n\t",@{$self->{'iFiltering'}});
       
   864 		}		
       
   865 	elsif (@{$self->{iFilter}}) { # can't have both -filter and complex filtering
       
   866 		foreach ( @{$self->{iFilter}}) {
       
   867 			if($_ ne '') {$filters.="<filter accept='$_'/>\n\t";}
       
   868 		} 
       
   869 	}
       
   870 		
       
   871 	my $ignore='';
       
   872 
       
   873 	foreach ( @{$self->{iIgnore}}){
       
   874 		if(/^(.*):(.*)$/) {$ignore.="<ignore type='$1' name='$2'/>\n\t"}
       
   875 	}
       
   876 		
       
   877 	
       
   878 	my $optional = $self->MakeAttirbutes(
       
   879 		'iCopyright' 	=> 'copyright',
       
   880 		'iDistribution'  		=> 'distribution',
       
   881 		'iRevision'  		=> 'revision',
       
   882 		'iDepsFile'  		=> 'deps',
       
   883 		'iLink'  		=> 'link',
       
   884 		'iRevisionType'  => 'revision-type',
       
   885 		'iVersions' 	=>	'version-list'
       
   886 		);
       
   887 
       
   888 	if($self->{iRelease} ne '') {$optional .= " ver='$self->{iRelease}'"}
       
   889 	elsif($self->{iGuessVer} eq 'Future' ) {$optional .= " ver='$self->{iGuessVer}'"}
       
   890 
       
   891 
       
   892 	my $layout = $self->MakeAttirbutes(
       
   893 		'iDetail'  		=> 'detail',
       
   894 		'iDetailType'  		=> 'detail-type',
       
   895 		'iPageWidth' 	=> 'page-width',
       
   896 		'iPrintResolution' 	=> 'resolution',
       
   897 		'iModelFont' 	=> 'font'
       
   898 		);
       
   899 	if($self->{iStatic}) {$layout .= " static='true'"}
       
   900 	my $legend = '';
       
   901 	my @legendmap = (
       
   902 		'iColor',	'colors',
       
   903 		'iStyle',	'styles',
       
   904 		'iOverlay',	'patterns',
       
   905 		'iBorder',	'borders'
       
   906 		); # order is important
       
   907 	for(my $i=0; $i<$#legendmap;$i+=2){
       
   908 		my $cur='#'.$infoMap{$legendmap[$i]};
       
   909 		my $count = scalar(@{$self->{$legendmap[$i]}});
       
   910 		 if ($count==0 || ($count==1 && $self->{$legendmap[$i]}->[0] eq '' )) {$cur='@shapes'."#$legendmap[$i+1]"}
       
   911 		$legend .= "\t\t\t<legend use=\"$cur\"/>\n";
       
   912 	}
       
   913 	foreach my $note (@{$self->{iLegendNote}})
       
   914 		{
       
   915 		if(!($note=~/&#?[0-9a-z]+;/i))
       
   916 			{	# if not entity-encoded, entity encode the stuff
       
   917 			$note=~ s/([&<>\x7f-\xff])/"&#".ord($1).";"/eg;
       
   918 			}
       
   919 		$legend .= "\t\t\t<note width='auto'>$note</note>";
       
   920 		}
       
   921 	
       
   922 	my $legendOptions;
       
   923 	if($self->{iLegendWidth}) {$legendOptions .= ' width="' .$self->{iLegendWidth} .'"'}
       
   924 	if($self->{iLegendMaxScale}) {$legendOptions .= ' maxscale="' .$self->{iLegendMaxScale} .'"'}
       
   925 	if($self->{iTitleScale}) {$legendOptions .= ' title-scale="' .$self->{iTitleScale} .'"'}
       
   926 	foreach my $line (<INPUT>)
       
   927 		{
       
   928 		my $cur='';
       
   929 		$line =~ s/___SYMBIAN_OS_RELEASE___/$self->{iRelease}/g;	# not used
       
   930 		$line =~ s/___NAME___/$self->{iName}/g;
       
   931 		$line =~ s/___LABEL___/$self->{iLabel}/g;
       
   932 		$line =~ s/___REVISION_TYPE___/$self->{iRevisionType}/g;	# not used
       
   933 		$line =~ s/___LINK___/$self->{iLink}/g;	# not used
       
   934 		$line =~ s/___OPTIONAL___/$optional/g;
       
   935 		$line =~ s/___LAYOUT_OPTIONS___/$layout/g;
       
   936 		$line =~ s/___FILTERS___/$filters/g;
       
   937 		$line =~ s/___IGNORE___/$ignore/g;
       
   938 		$line =~ s/___LEGEND___/$legend/g;
       
   939 		$line =~ s/___LEGEND_TITLE___/$self->{iLgdTitle}/g;
       
   940 		$line =~ s/___LEGEND_OPTIONS___/$legendOptions/g;
       
   941 		$line =~ s/___SHAPES_XML___/$self->{iShapes}/g;
       
   942 		$line =~ s/___SYSTEM_DEFINITIONS___/$sysdefTagsForModelTemplate/; # should be only one incident of it
       
   943 		$line =~ s/___DISPLAY___/$display/g;
       
   944 		$line =~ s/\sshapes=""//g; # remove empty attribute
       
   945 		print OUTPUT $line;
       
   946 		}
       
   947 	close INPUT;
       
   948 	close OUPUT;
       
   949 
       
   950 	# Open and close the file so that it can flush itself:
       
   951 	open (OUTPUT, "$modelXml") or &Logger::LogError("Xalan error ($error) occured in Step 1 of SVG building...", KOldSystemModelGenerator, 1);
       
   952 	close OUTPUT;
       
   953 	return $modelXml;
       
   954 	}
       
   955 
       
   956 sub GetXsltDir()
       
   957 	{
       
   958 	my $self = shift;
       
   959 	my $xsltDir = $FindBin::Bin."/svg";  # calcluated w.r.t old directory
       
   960 	$xsltDir = $FindBin::Bin."/src/old/svg" if ! -d $xsltDir; # calculated w.r.t the root directory
       
   961 	$xsltDir = $FindBin::Bin  if ! -d $xsltDir; # calculated w.r.t the /svg directory
       
   962 	return $xsltDir;
       
   963 	}
       
   964 
       
   965 
       
   966 sub FileAsUrl() 
       
   967 	{
       
   968 	my $file = $_[0];
       
   969 	if($file=~/^..+:/){ return $file}	# already a URL
       
   970 	if(-f $file)
       
   971 		{ # abs_path only works on dirs, so strip off file name and put it back when done
       
   972 		if(! ($file=~/^[a-z]:[\\\/][^\\\/]+$/i))
       
   973 			{ # if it's in the root dir, do nothing
       
   974 			my $tail = "/$file";
       
   975 			# if it's just a file name, need to find cwd;
       
   976 			if($file =~ s,([\\/][^\\/]+)$,,)
       
   977 				{
       
   978 				$tail = $1;
       
   979 				}
       
   980 			else {$file = "."}
       
   981 			$file = abs_path($file)."$tail";
       
   982 			}
       
   983 		} 
       
   984 	elsif (-d $file)
       
   985 		{
       
   986 		$file = abs_path($file);
       
   987 		}  # else does not exist, so just convert to unix-style path
       
   988 	$file=~tr/\\/\//;	
       
   989 	return "file:///$file";
       
   990 	}
       
   991 
       
   992 
       
   993 sub RunCmd() {
       
   994 	my $command = shift;
       
   995 	open(EXE,"$command 2>&1|");
       
   996 	while(<EXE>){
       
   997 		chomp;
       
   998 		s/^XSLT Message: //;
       
   999 		s/\.Source tree node:.*$//;
       
  1000 		if($_ ne '') {
       
  1001 			if(s/^note: //i) {
       
  1002 				&Logger::LogInfo($_, KOldSystemModelGenerator,2, 100);
       
  1003 			} elsif(s/^Warning: //) {
       
  1004 				&Logger::LogWarning($_,  KOldSystemModelGenerator,2, 600);
       
  1005 			} elsif(s/^Error: //i) {
       
  1006 				&Logger::LogError($_,  KOldSystemModelGenerator,2, 400);
       
  1007 			} else {
       
  1008 				print STDERR "$_\n";
       
  1009 			}
       
  1010 		}
       
  1011 	}
       
  1012 	close(EXE);
       
  1013 	return $?;
       
  1014 }
       
  1015 
       
  1016 sub ShouldCreateDepmodel()
       
  1017 	{
       
  1018 	my $self = shift;
       
  1019 	if ($self->{iDepsFile})
       
  1020 		{
       
  1021 		return 1;
       
  1022 		}
       
  1023 	my $model = $self->getModel();
       
  1024 	my $t = $/;
       
  1025 	$/='>';
       
  1026 	open(M,$model);
       
  1027 	while(<M>)
       
  1028 		{
       
  1029 		if(/<model\s/){last}
       
  1030 		}
       
  1031 	close M;
       
  1032 	$/ = $t;
       
  1033 	return /\sdeps=/;
       
  1034 	}
       
  1035 
       
  1036 sub XsltTransform()
       
  1037 	{
       
  1038 	my $xslt = shift;
       
  1039 	my $from = shift;
       
  1040 	my $to = shift;
       
  1041 	my $indent = shift;
       
  1042 	my %params = %{$_[0]};
       
  1043 	my $xsltParams;
       
  1044 
       
  1045 	# windows-specific stuff follows
       
  1046 
       
  1047 	if(! ($xslt=~/^..+:/)) {$xslt	=~ s#\/#\\#g}			#it's not a URL
       
  1048 	if(! ($from=~/^..+:/)) {$from	=~ s#\/#\\#g}			#it's not a URL
       
  1049 	if(! ($to=~/^..+:/)) {$to	=~ s#\/#\\#g}			#it's not a URL
       
  1050 
       
  1051 	while (my($p,$v) = each(%{$_[0]}))
       
  1052 		{
       
  1053 		$v =~ s/"/&quot;/g;	#"		
       
  1054 		$xsltParams.= " -p $p \"$v\"";
       
  1055 		}
       
  1056 
       
  1057 	my $command = &SysModelGen::Xalan();
       
  1058 	$command =~ s#\/#\\#g;
       
  1059 	$command .= $xsltParams;
       
  1060 	if($indent >=0) {
       
  1061 		$command .= " -i $indent";
       
  1062 	}
       
  1063 	if($to ne '') {
       
  1064 		$command .= " -o \"$to\"";
       
  1065 	}
       
  1066 	$command.=" \"$from\" \"$xslt\"";
       
  1067 	&Logger::LogInfo("System Call: $command", 800);
       
  1068 	if($to eq '') {return `$command`}
       
  1069 	return &RunCmd($command);
       
  1070 	}
       
  1071 
       
  1072 sub Draw()
       
  1073 	{
       
  1074 	my $self = shift;
       
  1075 	my $genSvg = $self->{'iDiagram'} ne '';
       
  1076 	my $genCsv = $self->{'iOutputCsv'} ne '';
       
  1077 	my $genXml = $self->{'iOutputXml'} ne '';
       
  1078 	
       
  1079 	if(!$genSvg && !$genCsv && !$genXml)  
       
  1080 		{
       
  1081         &Logger::LogFatal("Must specify at least one type of output file. Cannot continue...", KOldSystemModelGenerator, 0,Logger::KNothingToDo);		
       
  1082 		}
       
  1083 	
       
  1084 	&Logger::LogInfo("Creating sysmodel.svg...", KOldSystemModelGenerator,0);
       
  1085 	
       
  1086 	# Step 0:
       
  1087 	# Prepare some file names and create output directory:
       
  1088 
       
  1089 	# construct full path name:
       
  1090 	($self->{iRootDirectory} = cwd ) =~ s#\/#\\#g;
       
  1091 	chdir($self->{iTemporaryDirectory});
       
  1092 	my $tempDirectoryPathname = cwd; # now gives the full path name $self->{iTemporaryDirectory}
       
  1093 	chdir($self->{iRootDirectory}); # change back!
       
  1094 	
       
  1095 	my $xsltDir = $self->GetXsltDir();	
       
  1096 	
       
  1097 	my $tempStuctureFile = "$tempDirectoryPathname/system_model_svg_tmp.xml";
       
  1098 	my $tempXslFile = "$tempDirectoryPathname/system_model_svg_tmp.xsl";
       
  1099 	my $tempModelFile = "$tempDirectoryPathname/model_tmp.svg";
       
  1100 	my $tempModelFile2 = "$tempDirectoryPathname/model_tmp2.svg";
       
  1101 	my $modelXsl = $xsltDir."/Model.xsl";
       
  1102 	
       
  1103 	my $modelXml = $self->getModel();
       
  1104 	 
       
  1105 	# Step 2
       
  1106 	# xalan -i 2 model.xml model.xsl > tmp.xml
       
  1107 	$error = &XsltTransform($modelXsl,$modelXml,$tempStuctureFile,1,	$self->{'iXsltParam'});
       
  1108 				
       
  1109 	&Logger::LogError("Xalan error ($error) occured in combining sysdefs", KOldSystemModelGenerator, 1) if $error;
       
  1110 
       
  1111 	# Step 3 - validation
       
  1112 	# xalan tmp.xml validate.xsl
       
  1113 	if($self->{iWarningLevel} == LogItem::VERBOSE )
       
  1114 		{
       
  1115 		my $errors = &XsltTransform($xsltDir."/validate.xsl",$tempStuctureFile,'',-1);
       
  1116 		&Logger::LogList(split(/\n/,$errors));
       
  1117 		}
       
  1118 	if($genSvg)
       
  1119 		{ # only needed for model building 
       
  1120 		
       
  1121 		# Step 4
       
  1122 		&Logger::LogInfo("Creating styling XSLT...", KOldSystemModelGenerator, 1);
       
  1123 		$error = &XsltTransform("$xsltDir/Shapes.xsl",$modelXml,$tempXslFile,1,
       
  1124 				{%{$self->{'iXsltParam'}},'Model-Transform' => "'".&FileAsUrl($modelXsl)."'" });
       
  1125 		&Logger::LogError("Xalan error ($error) occured generating Styling transform", KOldSystemModelGenerator, 2) if $error;
       
  1126 	
       
  1127 		# Step 5
       
  1128 		&Logger::LogInfo("Generating SVG model...", KOldSystemModelGenerator, 1);
       
  1129 		$error = &XsltTransform($tempXslFile,$tempStuctureFile,$tempModelFile,1,$self->{'iXsltParam'});
       
  1130 		&Logger::LogError("Xalan error ($error) occured in building SVG", KOldSystemModelGenerator, 2) if $error;
       
  1131 
       
  1132 		if ($self->ShouldCreateDepmodel()) {	# insert as 1st transform
       
  1133 			@ARGV=( $xsltDir."/Postprocess.xsl",'-',@ARGV)
       
  1134 		}
       
  1135 		my $tmpsvg = $tempModelFile;
       
  1136 		while(scalar(@ARGV)) {
       
  1137 			my $transform = shift(@ARGV);
       
  1138 			my $datafile = shift(@ARGV);
       
  1139 			if($datafile eq '""' || $datafile eq "''") {$datafile=''}	# not sure if this will work, but it should fix cygwin troubles
       
  1140 			if($datafile eq '-') {$datafile = &FileAsUrl($tempStuctureFile)}
       
  1141 			elsif($datafile ne '') {$datafile = &FileAsUrl($datafile)}
       
  1142 			# save to the output if this is the last transform
       
  1143 			# otherwise save to tempModelFile2 if reading from tempModelFile, and vis versa
       
  1144 			my $saveto = $self->{'iDiagram'};
       
  1145 			if(scalar(ARGV))	 {
       
  1146 				$saveto = ($tmpsvg eq $tempModelFile) ? $tempModelFile2 : $tempModelFile;
       
  1147 			}
       
  1148 			# Step 6
       
  1149 			# xalan  -i 2 -p Data tmp.xml 'tmp.svg' postprocess.xsl> final.svg
       
  1150 			my %p; 
       
  1151 			if($datafile ne '') {
       
  1152 				$p{'Data'}="'$datafile'";	# optional -- only if needed for transform
       
  1153 			}
       
  1154 			$error = &XsltTransform($transform,$tmpsvg,$saveto,1,\%p);
       
  1155 			&Logger::LogError("Xalan error ($error) occured in post-processing SVG file", KOldSystemModelGenerator, 2) if $error;
       
  1156 
       
  1157 			$tmpsvg = $saveto; # read from this next time.
       
  1158 		}
       
  1159 		if ($tmpsvg ne $self->{'iDiagram'}) {
       
  1160 			open(OUT,">".$self->{iDiagram});
       
  1161 			open(IN,$tmpsvg);
       
  1162 			print OUT <IN>;
       
  1163 			close OUT;
       
  1164 			close IN;
       
  1165 		}
       
  1166 	
       
  1167 		my $zipname = $self->{iDiagram};
       
  1168 		my $unzipname = $zipname;
       
  1169 		$zipname =~ s/\.svg$/.svgz/i;
       
  1170 		$unzipname =~ s/\.svgz$/.svg/i;
       
  1171 		my $compressed = 0;
       
  1172 		if($self->{iCompress})
       
  1173 			{
       
  1174 			my $gzip = &SysModelGen::GzipCommand();
       
  1175 			if($gzip)
       
  1176 				{
       
  1177 				my $command = "$gzip ".$self->{iDiagram};
       
  1178 				&Logger::LogInfo("System Call: $command", KOldSystemModelGenerator);
       
  1179 				$error = &RunCmd($command);# this should generate the sysmodel.svg in the output directory
       
  1180 				&Logger::LogError("Gzip error ($error) occured when comrpessing SVG", KOldSystemModelGenerator, 1) if $error;
       
  1181 				&Logger::LogInfo("Renaming output to : $zipname", KOldSystemModelGenerator);		
       
  1182 				rename $self->{iDiagram}.".gz", $zipname;
       
  1183 				$compressed = 1;
       
  1184 				}
       
  1185 			}
       
  1186 		if(!$compressed && $unzipname ne $self->{iDiagram}) 
       
  1187 			{
       
  1188 			&Logger::LogInfo("Renaming output to : $unzipname", KOldSystemModelGenerator);		
       
  1189 			rename $self->{iDiagram}, $unzipname;	
       
  1190 			}
       
  1191 		}
       
  1192 	# create CSV if desired
       
  1193 	if($genCsv)
       
  1194 		{
       
  1195 		&Logger::LogInfo("Generating CSV output", KOldSystemModelGenerator, 0);
       
  1196 		my %p;
       
  1197 		if($self->{iCsvColumns})
       
  1198 			{
       
  1199 			$p{'atts'}="'".$self->{iCsvColumns}."'";
       
  1200 			}
       
  1201 		if($self->{iCsvLabels})
       
  1202 			{
       
  1203 			$p{'labels'}="'".$self->{iCsvLabels}."'";
       
  1204 			}
       
  1205 		$error = &XsltTransform($xsltDir."/output-csv.xsl",$tempStuctureFile,$self->{iOutputCsv},-1,\%p);
       
  1206 		&Logger::LogError("Xalan error ($error) occured in CSV output...", KOldSystemModelGenerator, 1) if $error;
       
  1207 
       
  1208 		}
       
  1209 		
       
  1210 	# create sysdef XML if desired
       
  1211 	
       
  1212 	if($genXml)
       
  1213 		{
       
  1214 		&Logger::LogInfo("Generating XML output", KOldSystemModelGenerator, 0);
       
  1215 		$error = &XsltTransform($xsltDir."/output-sysdef.xsl",$tempStuctureFile,$self->{iOutputXml},1);
       
  1216 		&Logger::LogError("Xalan error ($error) occured in Sysdef output...", KOldSystemModelGenerator, 1) if $error;
       
  1217 		}
       
  1218 
       
  1219 	# delete the contents of the temp directory if -clean is specified by the user:
       
  1220 	if ($self->{iClean})
       
  1221 		{
       
  1222 		&Logger::LogInfo("Deleting contents of the temp directory $self->{iTemporaryDirectory}...", 100);
       
  1223 		$self->DeleteTempDirectory();
       
  1224 		}	
       
  1225 	}
       
  1226 
       
  1227 sub Downgrade()
       
  1228 	{
       
  1229 	my $self = shift;
       
  1230 	my $sysdef = shift;
       
  1231 	my $saveto = $self->{iTemporaryDirectory}."/".shift;
       
  1232 	my $sysdefurl=&FileAsUrl($sysdef);
       
  1233 	my $xsltDir = $self->GetXsltDir();	
       
  1234 	foreach(@{$self->{iSysDefFile}}) 
       
  1235 		{
       
  1236 		if($_ eq $sysdefurl)
       
  1237 			{
       
  1238 			$error = &XsltTransform("$xsltDir/sysdefdowngrade.xsl",$sysdef,$saveto,1);
       
  1239 			&Logger::LogError("Xalan error ($error) occured in downgrading $sysdef...", KOldSystemModelGenerator, 1) if $error;
       
  1240 			$_=&FileAsUrl($saveto);
       
  1241 			}
       
  1242 		}
       
  1243 	}
       
  1244 
       
  1245 
       
  1246 sub SystemModelXmlDataDir()
       
  1247 	{
       
  1248 	my $file = $FindBin::Bin."/src/old/resources/auxiliary";
       
  1249 	$file = $FindBin::Bin."/../resources/auxiliary" if ! -d $file; # calculated w.r.t the /svg directory
       
  1250 	return $file;
       
  1251 	}
       
  1252 
       
  1253 sub SystemModelColorsXmlFile()
       
  1254 	{
       
  1255 	my $colorsFile =  &SystemModelXmlDataDir()."/system_model_colors.xml";
       
  1256 	return $colorsFile;
       
  1257 	}
       
  1258 
       
  1259 
       
  1260 
       
  1261 sub CreateSysDefTagsForModelXML()
       
  1262 	{
       
  1263 	my $self = shift;
       
  1264 	my $sysdefXml = shift;
       
  1265 	my $srcvar = shift;
       
  1266 
       
  1267 	if($sysdefXml eq '')
       
  1268 		{
       
  1269 		&Logger::LogInfo("Cannot find System Definition file", 100);
       
  1270 		return;
       
  1271 		}
       
  1272 
       
  1273 	my $ret = "<sysdef href=\"".&FileAsUrl($sysdefXml)."\"";
       
  1274 	if($srcvar ne '') {$ret.=" root=\"$srcvar\""}
       
  1275 	$ret .=">\n" . 
       
  1276 		$self->MakeMultiInfo('iExtra' 	=> 'extra', 'iLevels'  	=> 'levels'	, 'iS12' => 's12');
       
  1277 	return "$ret\t</sysdef>\n";
       
  1278 	}
       
  1279 	
       
  1280 sub DeleteTempDirectory()
       
  1281 	{
       
  1282 	my $self = shift;
       
  1283 	# This will delete all files in the $self->{iTemporaryDirectory}
       
  1284 	rmtree $self->{iTemporaryDirectory};
       
  1285 	}
       
  1286 
       
  1287 sub Help()
       
  1288 	{
       
  1289 	my $self = shift;
       
  1290 format OK =
       
  1291  @<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
       
  1292 $param,                               $text,
       
  1293                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
       
  1294                        $text
       
  1295 .
       
  1296 my @list =(
       
  1297  'Switch',               'Explanation',
       
  1298  '------',               '-----------',
       
  1299 '-h' ,           'Help on usage',
       
  1300 	'-i'      ,      'An INI file listing one argument per line, with the syntax: <argument> = <value>',
       
  1301 	'==== Build Control  ====',
       
  1302   '-w'          ,  'Warning level. 1: errors only (default), 2: warnings as well as errors, 3: info messages, warnings and errors, 4: all plus deep syntax validation and reporting -- note that this can take a long time to compute so do not use this warning level by default',
       
  1303   '-tempdir',	    'Temporary directory for build files. Defaults to drawsvg_temp',
       
  1304   '-output', 		'The name of the file to save the built System Model SVG. If in the format filename.svgz, it will attempt to compress the file. If compression is not supported, it will rename the output to filename.svg. Defaults to sysmodel.svg or sysmodel.svgz if -compress is set.',
       
  1305   '-csv_output', 		'The name of the file to save a CSV description of the built System Model. Only items shown on the system model will be included.',
       
  1306   '-csv_columns', 	'Comma-separated list of columns to include in the output CSV.  This does nothing if -csv_output is not present. By default (if -csv_columns is not present), the columns will be a sorted list of all attributes on all items. ',
       
  1307   '-csv_labels', 	'Comma-separated list of columns labels include in the output CSV.  Do not use quotes or commas in label names. This does nothing if -csv_output is not present. If this list is shorter than -csv_columns, the remaining columns will use the attribute name as the label. ',
       
  1308   '-xml_output', 		'The name of the file to save a combined system definition XML. Only items shown in the built system model will be included.',
       
  1309   '-log'	,    'File in which to store output. Defaults to stdout',
       
  1310   '-compress', 	'If set, it will attempt to compress the output as an SVGZ file. In order to success gzip must be installed and in the PATH. This will also rename the output file from filename.svg to filename.svgz.',
       
  1311   '-clean'   ,        'Caution: if set, it will delete the contents of the temporary directory.',
       
  1312   "==== Files or URIs ====\nAll of these take a file name (relative or absolute path) or URI of a data source",
       
  1313 '-model', 'The location of the Model XML file to use to build the file.  If this is provided all other non-build control command line  and ini options are ignored.',
       
  1314 '-shapes', 'The location of the Shapes XML file used to provide rules to control  the display of the components on the model. If not present, default behaviour  (in Shapes.xml) is used. This and the default bahaviours are overrriden by  using the -color, -border, -pattern, and -style options. ',
       
  1315 '-localize', 'The location of the Localization file used to provide displayable names for the model entities. By default,  the provided  "display-names.xml" is used.',
       
  1316 '-s12', 'The location of the Schedule 12 XML file used to provide the border shapres of the components. If this a directory, the S12 XML file is found by appending "Symbian_OS_v[system_version]_Schedule12.xml" to the directory.',
       
  1317 '-levels', 'The location of the Levels XML file used to override the  stacking of collections. ',
       
  1318 '-sysinfo', 'The location of extra component information used to provided additional  properies for components.  By default,  the provided "SystemInfo.xml" is used.',
       
  1319 '-deps', 'The location of the Dependencies XML file used to draw the depmodel.  If not present, dependencies will not be drawn',
       
  1320 '-color', 'The location of a Values XML file used to specify per-component colours. If not present, the default colours are used.',
       
  1321 '-border-shape', 'The location of a Values XML file used to specify the shape (border)  of each component. If not present, the default borders are used.',
       
  1322 '-pattern', 'The location of a Values XML file used to specify per-component overlay patterns. If not present, the default patterns (for new  and reference components) are used.',
       
  1323 '-border-style', 'The location of a Values XML file used to specify per-component border  styles. If not present, the default border styles are used. ',
       
  1324 '-link','The base URL to use for all hyperlinks in the model. A base URL will be appended by the type and name (e.g. Blocks/Comms%20Services.html) of the items to create the full URL of the linked file. Window directories will be converted into file URIs.',
       
  1325 "==== Labels ====\nAll of these take a plain text value which is displayed on the model",
       
  1326 '-system_name', 'The name of the product described in the model. It appears at  the bottom right. Defaults to "Symbian OS"',
       
  1327 '-system_version', 'The version of the product described in the model. It appears  at the bottom right after the name.',
       
  1328 '-model_name', 'The label for the model. It appears at the bottom right,  under the name. Defaults to "System Model".',
       
  1329 '-model_version', 'A number which appears before th model-revision-type.   If specified this overrides the build number used by depmodel.  If not building depmodel, this defaults to "1"',
       
  1330 '-model_version_type', 'One of "draft", "issued", "build" or free-text value. Appears below the model label. If specified this overrides the build number used by DepToolkit.If not building depmodel, this defaults to "draft"',
       
  1331 '-copyright', 'The copyright to appear in the lower left. Set to empty string to leave out. Defaults to "[this year] Nokia Corporation"',
       
  1332 '-distribution', 'Text to appear on the bottom centre to indicate to whom the  model can be show. Informational only. Suggested values are "internal", "secret" or "unrestrictred". Not shown if not set.',
       
  1333 '-legend_title', 'The title to appear in the leftmost part of the legend. Defautls to "Key"',
       
  1334 '-note', 'Free text to appear inside the legend box, on the rightmost side. If multiple ones are provided, they will appear as separate boxes from left to right. Newlines and other special characters can be entity-encoded (e.g. &#xa;)',  
       
  1335 "==== Model Control  ====",
       
  1336 '-sysdef [uri-list]',   'Comma-separated list of locations for the System Definition XML file(s) used to build the model. Layers in the files will be  stacked on top of each other in order, from bottom to top.',
       
  1337 '-coreos [on/off/new]', 'Turn on or off Core OS colouring, or use the new colouring for 9.5 and later models. Defaults to "off" for model versions before 9.4 or those with no specified version, "on" for 9.4 and "new" for 9.5 and later',
       
  1338 '-filter [filter-name]', 'The name of a filter to turn on when building the model.  All filters on an item must be present in this list in order for that item to appear. Can have any number of these Defaults to "java" and "gt"',
       
  1339 '-filter-has [filter-name]', 'Like -filter, except any filter on an item must be present in this list in order for that item to appear. Include "*" in the list in order to show items with no filters. Equivalent to "-show-attr filter xxx"',
       
  1340 '-ignore [item]', 'A model entity to not draw, in the  form "[item-type]:[item-name]". Any number of these can be used. Defaults to "layer:Tools and Utils and SDKENG" ,"layer:MISC", "block:Techview"',
       
  1341 '-show-attr [attr[=val]]', 'A mechanism of filtering which allows filtering based on component attribute values. If a value is set for that attribute, the component will be shown. Use in conjunction with -hide-attr for fine contol of what is shown. "class" and "filter" attribtues are handled specially -- see the documentation for details',
       
  1342 '-hide-attr [attr[=val]]', 'A mechanism of filtering which allows filtering based on component attribute values. If a value is set for that attribute, the component will not be shown on the model. Use in conjunction with -show-attr for fine contol of what is shown. "class" and "filter" attribtues are handled specially -- see the documentation for details',
       
  1343 '-detail [item-type]' , 'The type of the smallest System Model entity to draw. One of "layer", "block", "subblock", "collection" or "component".  Defaults to "component"',		
       
  1344 '-detail-type [type]' , 'If set to "fixed", the smallest System Model entity drawn will have a fixed width (rather then sized by their invisible components). This can be used to reduce the size and complexity of the overall model.',
       
  1345 '-page-width [length]', 'The width of the drawn image (with units). If not specified it will fit the viewer window. Valid units: "in", "mm", "cm", "px", "pt"',
       
  1346 '-static', 'If present, the model will not have any mouseover effects (this is  overriden by builing the depmodel).',
       
  1347 '-logo [file]', 'If present, the logo will be drawn in the lower-left corner of the model. If the logo is an SVG file, -logo-width and -logo-height are optional, otherwise the must both be specified',
       
  1348 '-logo-height [length]', 'Specifies the height of the logo (if any) in mm. Width is scaled along with height unless otherwise specified. Both width and height MUST be specified if a bitmap image is used',
       
  1349 '-logo-width [length]', 'Specifies the width of the logo (if any) in mm. Height is scaled along with width unless otherwise specified. Both width and height MUST be specified if a bitmap image is used',
       
  1350 '-legend-width [%]', 'The percent width of the model the legend takes up. This will scale the size of the legend and model title, but not the logo, to fill the specified space. If a logo is included, but no width specified, the legend cannot be scaled since it will not be able to determine the available space. Note that that -max-legend-scale will further limit the potential width.',
       
  1351 '-legend-max-scale [scale]', 'Specifies the maximum scale factor for resizing the legend. If this is present and -legend-width is not, the legend and title will scale to 100% of the available width. If both are present the scale factor will take precedent. If neither is present, the legend will not resize. Note that when this is used, the legend can shrink if it would normally be wider than the model.',
       
  1352 '-title-scale [scale]', 'Specifies the scale factor for the size of the title font (the text in the lower right). Use this instead of CSS to control the size, since the model generator needs to explicitly know how much space to allocate for the title.',
       
  1353 '-model_font [font]', 'The name of the base font to use to draw the model. This will be overriden by any custom CSS in the Shapes XML',
       
  1354 '-dpi [number]', 'The DPI to use when printing from the Adobe SVG Viewer. If not present, it will print well at A4 size. A value of 300 will look good on A3 size paper'
       
  1355   );
       
  1356 print STDERR "Usage: DrawSvg.pl [Arguments] [Transform Data-file] ...\n\nArguments:\n";
       
  1357   my $head=2;
       
  1358 while(@list) {
       
  1359 	$param = shift(@list);
       
  1360 	if($head<=0 and !($param=~/^-/)){print "\n$param\n";next;}
       
  1361 	$text = shift(@list);
       
  1362 	write OK ;
       
  1363 	$head--;
       
  1364 }
       
  1365 	return;
       
  1366 	}
       
  1367 
       
  1368 1;