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