You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by hd...@apache.org on 2013/12/11 09:49:18 UTC

svn commit: r1550072 [7/9] - in /openoffice/branches/rejuvenate01: ./ main/accessibility/source/extended/ main/accessibility/source/standard/ main/basic/source/runtime/ main/bridges/prj/ main/chart2/source/controller/dialogs/ main/cui/source/dialogs/ m...

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/setupscript.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/setupscript.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/setupscript.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/setupscript.pm Wed Dec 11 08:49:16 2013
@@ -31,6 +31,8 @@ use installer::remover;
 use installer::scriptitems;
 use installer::ziplist;
 
+use strict;
+
 #######################################################
 # Set setup script name, if not defined as parameter
 #######################################################
@@ -74,231 +76,161 @@ sub set_setupscript_name
 # Reading script variables from installation object of script file
 #####################################################################
 
-sub get_all_scriptvariables_from_installation_object
+sub get_all_scriptvariables_from_installation_object ($$)
 {
-	my ($scriptref) = @_;
+	my ($scriptref, $script_filename) = @_;
 	
-	my @installobjectvariables;
-
-	for ( my $i = 0; $i <= $#{$scriptref}; $i++ )
-	{
-		my $line = ${$scriptref}[$i];
+	my $installobjectvariables = {};
 
-		if ( $line =~ /^\s*Installation\s+\w+\s*$/ )	# should be the first line
-		{
-			my $counter = $i+1;
-			my $installline = ${$scriptref}[$counter];	
-			
-			while (!($installline =~ /^\s*End\s*$/ ))
-			{
-				if ( $installline =~ /^\s*(\w+)\s+\=\s*(.*?)\s*\;\s*$/ )
-				{
-					my $key = $1;
-					my $value = $2;
-					
-					# removing leading and ending " in $value
-					
-					if ( $value =~ /^\s*\"(.*)\"\s*$/ )
-					{
-						$value = $1;	
-					}
-					
-					$key = "\%" . uc($key);  # $key is %PRODUCTNAME
-					
-					my $input = $key . " " . $value . "\n";	  # $key can only be the first word
+    my $firstline = $scriptref->[0];
+    if ($firstline !~ /^\s*Installation\s+\w+\s*$/)
+    {
+        installer::logger::PrintError("did not find 'Installation' keyword in first line of %s\n",
+            $script_filename);
+    }
+    foreach my $line (@$scriptref)
+    {
+		next if $line =~ /^\s*Installation\s+\w+\s*$/; # Already processed.
+        last if $line =~ /^\s*End\s*$/;
+
+        if ($line =~ /^\s*(\w+)\s+\=\s*\"?(.*?)\"?\s*\;\s*$/ )
+        {
+            my ($key, $value) = ($1, $2);
 					
-					push(@installobjectvariables ,$input);
-				}
-
-				$counter++;			
-				$installline = ${$scriptref}[$counter];	
-			}
-		}
+            $installobjectvariables->{uc($key)} = $value;
+        }
 
-		last;	# not interesting after installation object
 	}
 
-	return \@installobjectvariables;
+	return $installobjectvariables;
 }
 
 ######################################################################
 # Including LCPRODUCTNAME into the array
 ######################################################################
 
-sub add_lowercase_productname_setupscriptvariable
+sub add_lowercase_productname_setupscriptvariable ($)
 {
 	my ( $variablesref ) = @_;
 
-	for ( my $j = 0; $j <= $#{$variablesref}; $j++ )
-	{
-		my $variableline = ${$variablesref}[$j];
-
-		my ($key, $value);
-				
-		if ( $variableline =~ /^\s*\%(\w+?)\s+(.*?)\s*$/ )
-		{
-			$key = $1;
-			$value = $2;
-			
-			if ( $key eq "PRODUCTNAME" )
-			{
-				my $newline = "\%LCPRODUCTNAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				my $original = $value;
-				$value =~ s/\s*//g; 
-				$newline = "\%ONEWORDPRODUCTNAME " . $value . "\n";
-				push(@{$variablesref} ,$newline);
-				$newline = "\%LCONEWORDPRODUCTNAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				$value = $original;
-				$value =~ s/\s*$//g;
-				$value =~ s/^\s*//g;
-				$value =~ s/ /\%20/g;
-				$newline = "\%MASKEDPRODUCTNAME " . $value . "\n";
-				push(@{$variablesref} ,$newline);				
-				$value = $original;
-				$value =~ s/\s/\_/g; 
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $1 . $2 . $4; }
-				$newline = "\%UNIXPRODUCTNAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				$newline = "\%SYSTEMINTUNIXPACKAGENAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $1 . $2 . $4; }
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $2 . $4; }
-				$newline = "\%UNIXPACKAGENAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				$value = $original;
-				$value =~ s/\s/\_/g; 
-				$value =~ s/\.//g; 
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $1 . $2 . $4; }
-				$newline = "\%WITHOUTDOTUNIXPRODUCTNAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $1 . $2 . $4; }
-				# if ( $value =~ /^\s*(.*?)\_(\w)(.*?)\_(\w)(.*)\s*$/ ) { $value = $2 . $4; }
-				$newline = "\%WITHOUTDOTUNIXPACKAGENAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				$newline = "\%SOLARISBRANDPACKAGENAME " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);
-				$value = $original;
-			}
-			elsif  ( $key eq "PRODUCTEXTENSION" )
-			{
-				my $newline = "\%LCPRODUCTEXTENSION " . lc($value) . "\n";
-				push(@{$variablesref} ,$newline);			
-			}
-			elsif  ( $key eq "PRODUCTVERSION" )
-			{
-				$value =~ s/\.//g; 
-				my $newline = "\%WITHOUTDOTPRODUCTVERSION " . $value . "\n";
-				push(@{$variablesref} ,$newline);			
-			}
-			elsif  ( $key eq "OOOBASEVERSION" )
-			{
-				$value =~ s/\.//g; 
-				my $newline = "\%WITHOUTDOTOOOBASEVERSION " . $value . "\n";
-				push(@{$variablesref} ,$newline);			
-			}
-			
+    my %additional_variables = ();
+    
+	while (my ($key, $value) = each %$variablesref)
+	{
+        if ($key eq "PRODUCTNAME")
+        {
+            $additional_variables{"LCPRODUCTNAME"} = lc($value);
+            my $original = $value;
+            $value =~ s/\s+//g; 
+            $additional_variables{"ONEWORDPRODUCTNAME"} = $value;
+            $additional_variables{"LCONEWORDPRODUCTNAME"} = lc($value);
+            $value = $original;
+            $value =~ s/(^\s+|\s+$)//g;
+            $value =~ s/ /\%20/g;
+			$additional_variables{"MASKEDPRODUCTNAME"} = $value;
+            $value = $original;
+            $value =~ s/\s/\_/g; 
+            $additional_variables{"UNIXPRODUCTNAME"} = lc($value);
+            $additional_variables{"SYSTEMINTUNIXPACKAGENAME"} = lc($value);
+            $additional_variables{"UNIXPACKAGENAME"} = lc($value);
+            $value = $original;
+            $value =~ s/\s/\_/g; 
+            $value =~ s/\.//g; 
+            $additional_variables{"WITHOUTDOTUNIXPRODUCTNAME"} = lc($value);
+            $additional_variables{"WITHOUTDOTUNIXPACKAGENAME"} = lc($value);
+            $additional_variables{"SOLARISBRANDPACKAGENAME"} = lc($value);
+        }
+        elsif  ($key eq "PRODUCTEXTENSION")
+        {
+            $additional_variables{"LCPRODUCTEXTENSION"} = lc($value);
+        }
+        elsif  ($key eq "PRODUCTVERSION")
+        {
+            $value =~ s/\.//g; 
+            $additional_variables{"WITHOUTDOTPRODUCTVERSION"} = $value;
+        }
+        elsif  ($key eq "OOOBASEVERSION")
+        {
+            $value =~ s/\.//g; 
+            $additional_variables{"WITHOUTDOTOOOBASEVERSION"} = $value;
 		}
 	}
+
+	while (my ($key, $value) = each %additional_variables)
+    {
+        $variablesref->{$key} = $value;
+    }
 }
 
 ######################################################################
 # Resolving the new introduced lowercase script variables
 ######################################################################
 
-sub resolve_lowercase_productname_setupscriptvariable
+sub resolve_lowercase_productname_setupscriptvariable ($)
 {
-	my ( $variablesref ) = @_;
-
-	my %variables = ();
+	my ($variablesref) = @_;
 
-	# First step: Collecting variables
-
-	for ( my $j = 0; $j <= $#{$variablesref}; $j++ )
-	{
-		my $variableline = ${$variablesref}[$j];
-
-		my ($key, $value);
-				
-		if ( $variableline =~ /^\s*\%(\w+?)\s+(.*?)\s*$/ )
-		{
-			$key = $1;
-			$value = $2;
-			$variables{$key} = $value;
-		}
-	}
-	
-	# Second step: Resolving variables
-	
-	for ( my $j = 0; $j <= $#{$variablesref}; $j++ )
-	{				
-		if ( ${$variablesref}[$j] =~ /\$\{(.*?)\}/ )
-		{
-			my $key = $1;
-			${$variablesref}[$j] =~ s/\$\{\Q$key\E\}/$variables{$key}/g;			
+    while (my ($key,$value) = each %$variablesref)
+    {
+		if ($value =~ /\$\{(.*?)\}/)
+		{
+            my $varname = $1;
+            my $replacement = $variablesref->{$varname};
+            my $new_value = $value;
+            $new_value =~ s/\$\{\Q$varname\E\}/$replacement/g;
+            $variablesref->{$key} = $new_value;
 		}
 	}
-
 }
 
+
+
+
 ######################################################################
 # Replacing all setup script variables inside the setup script file
 ######################################################################
 
-sub replace_all_setupscriptvariables_in_script
+sub replace_all_setupscriptvariables_in_script ($$)
 {
-	my ( $scriptref, $variablesref ) = @_;
+	my ($script_lines, $variables) = @_;
 
 	installer::logger::include_header_into_globallogfile("Replacing variables in setup script (start)");
 
-	# make hash of variables to be substituted if they appear in the script
-	my %subs;
-	for ( my $j = 0; $j <= $#{$variablesref}; $j++ )
-	{
-		my $variableline = ${$variablesref}[$j];
-
-		if ( $variableline =~ /^\s*(\%\w+?)\s+(.*?)\s*$/ )
-		{
-			$subs{$1}= $2;
-		}
-	}
-
 	# This is far faster than running a regexp for each line
-	my $bigstring = '';
-	for my $line (@{$scriptref}) { $bigstring = $bigstring . $line; }
+	my $bigstring = join("", @$script_lines);
 
-	foreach my $key ( keys %subs )
+	while (my ($key,$value) = each %$variables)
 	{
 		# Attention: It must be possible to substitute "%PRODUCTNAMEn", "%PRODUCTNAME%PRODUCTVERSIONabc"
-		my $value = $subs{$key};
-		$bigstring =~ s/$key/$value/g;
+		my $count = ($bigstring =~ s/%$key/$value/g);
+        if ($count > 0)
+        {
+            $installer::logger::Lang->printf("replaced %s %d times\n", $key, $count);
+        }
 	}
 
 	my @newlines = split /\n/, $bigstring;
-	$scriptref = \@newlines;
 
 	# now check for any mis-named '%' variables that we have left
 	my $num = 0;
-	for my $check (@newlines)
+	foreach my $line (@newlines)
 	{
 		$num++;
-		if ( $check =~ /^.*\%\w+.*$/ )
+		if ($line =~ /\%\w+/)
 		{
-			if (( $check =~ /%1/ ) || ( $check =~ /%2/ ) || ( $check =~ /%verify/ ))
+			if (( $line =~ /%1/ ) || ( $line =~ /%2/ ) || ( $line =~ /%verify/ ))
             {
                 next;
             }
-            $installer::logger::Global->printf(
-                "WARNING: mis-named or un-known '%s' variable in setup script at line %s:\n",
-                "%", $num);
-            $installer::logger::Global->printf("%s\n", $check);
+            $installer::logger::Info->printf(
+                "WARNING: mis-named or un-known %%-variable in setup script at line %s:\n",$num);
+            $installer::logger::Info->printf("%s\n", $line);
 		}
 	}
 
 	installer::logger::include_header_into_globallogfile("Replacing variables in setup script (end)");
 
-	return $scriptref;
+	return \@newlines;
 }
 
 #######################################################################
@@ -469,21 +401,13 @@ sub prepare_non_advertised_files
 # object, the installation object is more important
 #####################################################################################
 
-sub add_installationobject_to_variables
+sub add_installationobject_to_variables ($$)
 {
-	my ($allvariables, $allscriptvariablesref) = @_;
+	my ($variables, $script_variables) = @_;
 
-	for ( my $i = 0; $i <= $#{$allscriptvariablesref}; $i++ )
+	while (my ($key, $value) = each %$script_variables)
 	{
-		my $line = ${$allscriptvariablesref}[$i];
-	
-		if ( $line =~ /^\s*\%(\w+)\s+(.*?)\s*$/ )
-		{
-			my $key = $1;
-			my $value = $2;
-
-			$allvariables->{$key} = $value;	# overwrite existing values from zip.lst
-		}
+        $variables->{$key} = $value;	# overwrite existing values from zip.lst
 	}
 }
 
@@ -521,13 +445,9 @@ sub replace_preset_properties
 	my @presetproperties = ();
 	push(@presetproperties, "SOLARISBRANDPACKAGENAME");
 	push(@presetproperties, "SYSTEMINTUNIXPACKAGENAME");
-	# push(@presetproperties, "UNIXPACKAGENAME");
-	# push(@presetproperties, "WITHOUTDOTUNIXPACKAGENAME");
-	# push(@presetproperties, "UNIXPRODUCTNAME");
-	# push(@presetproperties, "WITHOUTDOTUNIXPRODUCTNAME");
 	
 
-	foreach $property ( @presetproperties )
+	foreach my $property (@presetproperties)
 	{
 		my $presetproperty = "PRESET" . $property;
 		if (( exists($allvariables->{$presetproperty}) ) && ( $allvariables->{$presetproperty} ne "" ))

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/systemactions.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/systemactions.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/systemactions.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/systemactions.pm Wed Dec 11 08:49:16 2013
@@ -451,16 +451,7 @@ sub create_directories
 
 		if (!($locallanguagesref eq "" ))	# this will be a path like "01_49", for Profiles and ConfigurationFiles, idt-Files
 		{
-			my $languagestring = $$languagesref;
-
-			if (length($languagestring) > $installer::globals::max_lang_length )
-			{
-				my $number_of_languages = get_number_of_langs($languagestring);
-				chomp(my $shorter = `echo $languagestring | md5sum | sed -e "s/ .*//g"`);
-				# $languagestring = $shorter;
-				my $id = substr($shorter, 0, 8); # taking only the first 8 digits
-				$languagestring = "lang_" . $number_of_languages . "_id_" . $id;				
-			}
+			my $languagestring = installer::languages::get_language_directory_name($$languagesref);
 
 			$path = $path . $languagestring  . $installer::globals::separator;
 			create_directory($path);
@@ -1719,36 +1710,48 @@ sub read_complete_directory
 # Version 2	
 ##############################################################
 
-sub read_full_directory {
+sub read_full_directory ($$$)
+{
 	my ( $currentdir, $pathstring, $collector ) = @_;
 	my $item;
 	my $fullname;
 	local *DH;
 
-	unless (opendir(DH, $currentdir))
-	{
-		return;
-	}
-	while (defined ($item = readdir(DH)))
-	{
-		next if($item eq "." or $item eq "..");
-		$fullname = $currentdir . $installer::globals::separator . $item;
-		my $sep = "";
-		if ( $pathstring ne "" ) { $sep = $installer::globals::separator; }
+    $installer::logger::Lang->printf("seaching files under '%s'\n", $currentdir);
 
-		if( -d $fullname)
-		{
-			my $newpathstring = $pathstring . $sep . $item;
-			read_full_directory($fullname, $newpathstring, $collector) if(-d $fullname);
-		}
-		else
-		{
-			my $content = $pathstring . $sep . $item;
-			push(@{$collector}, $content);
-		}
-	}
-	closedir(DH);
-	return 
+    my @directory_queue = [$currentdir, $pathstring];
+
+    while (scalar @directory_queue > 0)
+    {
+        my ($path, $relative_path) = @{shift @directory_queue};
+        my $start_count = scalar @$collector;
+
+        next unless opendir(DH, $path);
+
+        while (defined ($item = readdir(DH)))
+        {
+            next if($item eq "." or $item eq "..");
+            $fullname = $path . $installer::globals::separator . $item;
+            my $sep = "";
+            if ($relative_path ne "")
+            {
+                $sep = $installer::globals::separator;
+            }
+
+            if( -d $fullname)
+            {
+                push @directory_queue, [$fullname, $relative_path . $sep . $item];
+            }
+            else
+            {
+                my $content = $relative_path . $sep . $item;
+                push(@{$collector}, $content);
+            }
+        }
+        closedir(DH);
+        my $count = scalar @$collector - $start_count;
+        $installer::logger::Lang->printf("    found %d new files in '%s'\n", $count, $path);
+    }
 }
 
 ##############################################################

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/assembly.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/assembly.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/assembly.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/assembly.pm Wed Dec 11 08:49:16 2013
@@ -28,6 +28,8 @@ use installer::globals;
 use installer::worker;
 use installer::windows::idtglobal;
 
+use strict;
+
 ##############################################################
 # Returning the first module of a file from the
 # comma separated list of modules.
@@ -224,9 +226,9 @@ sub create_msiassembly_table
 # Returning the name for the table MsiAssemblyName
 ####################################################################################
 
-sub get_msiassemblyname_name
+sub get_msiassemblyname_name ($)
 {
-	( $number ) = @_;
+	my ($number) = @_;
 	
 	my $name = "";
 	
@@ -315,12 +317,9 @@ sub add_assembly_condition_into_componen
 	my $componenttablename = $basedir . $installer::globals::separator . "Componen.idt";
 	my $componenttable = installer::files::read_file($componenttablename);
 	my $changed = 0;
-	my $infoline = "";
 
-	for ( my $i = 0; $i <= $#{$installer::globals::msiassemblyfiles}; $i++ )
+	foreach my $onefile (@$installer::globals::msiassemblyfiles)
 	{
-		my $onefile = ${$installer::globals::msiassemblyfiles}[$i];
-		
 		my $filecomponent = get_msiassembly_component($onefile);
 	
 		for ( my $j = 0; $j <= $#{$componenttable}; $j++ )
@@ -342,13 +341,19 @@ sub add_assembly_condition_into_componen
 					
 					# $condition = "MsiNetAssemblySupport";
 					$condition = "DOTNET_SUFFICIENT=1";
-					$oneline = $component . "\t" . $componentid . "\t" . $directory . "\t" . $attributes . "\t" . $condition . "\t" . $keypath . "\n";
+					$oneline = join("\t",
+                        $component,
+                        $componentid,
+                        $directory,
+                        $attributes,
+                        $condition,
+                        $keypath) . "\n";
 					${$componenttable}[$j] = $oneline;
 					$changed = 1;
-					$infoline = "Changing $componenttablename :\n"; 
-					$installer::logger::Lang->print($infoline);
-					$infoline = $oneline; 
-					$installer::logger::Lang->print($infoline);
+                    
+					$installer::logger::Lang->printf("Changing %s :\n",  $componenttablename);
+					$installer::logger::Lang->print($oneline);
+                    
 					last;			
 				}		
 			}
@@ -359,8 +364,7 @@ sub add_assembly_condition_into_componen
 	{
 		# Saving the file
 		installer::files::save_file($componenttablename ,$componenttable);
-		$infoline = "Saved idt file: $componenttablename\n"; 
-		$installer::logger::Lang->print($infoline);
+		$installer::logger::Lang->printf("Saved idt file: %s\n", $componenttablename);
 	}
 }
 

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/component.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/component.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/component.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/component.pm Wed Dec 11 08:49:16 2013
@@ -31,6 +31,8 @@ use installer::globals;
 use installer::windows::idtglobal;
 use installer::windows::language;
 
+use strict;
+
 ##############################################################
 # Returning a globally unique ID (GUID) for a component
 # If the component is new, a unique guid has to be created.
@@ -39,9 +41,9 @@ use installer::windows::language;
 # Sample for a guid: {B68FD953-3CEF-4489-8269-8726848056E8}
 ##############################################################
 
-sub get_component_guid
+sub get_component_guid ($)
 {	
-	my ( $componentname, $componentidhashref ) = @_;
+	my ($componentname) = @_;
 	
 	# At this time only a template
 	my $returnvalue = "\{COMPONENTGUID\}";
@@ -49,6 +51,9 @@ sub get_component_guid
 	# Returning a ComponentID, that is assigned in scp project
 	if ( exists($installer::globals::componentid{$componentname}) )
 	{
+        $installer::logger::Lang->printf("reusing guid %s for component %s\n",
+            $installer::globals::componentid{$componentname},
+            $componentname);
 		$returnvalue = "\{" . $installer::globals::componentid{$componentname} . "\}";
 	}
 	
@@ -59,52 +64,48 @@ sub get_component_guid
 # Returning the directory for a file component.
 ##############################################################
 
-sub get_file_component_directory
+sub get_file_component_directory ($$$)
 {
-	my ($componentname, $filesref, $dirref) = @_; 
+    my ($componentname, $filesref, $dirref) = @_; 
 
-	my ($onefile, $component, $onedir, $hostname, $uniquedir);
-	my $found = 0;
+    my ($component,  $uniquedir);
 
-	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
-	{
-		$onefile = 	${$filesref}[$i];
-		$component = $onefile->{'componentname'};
-		
-		if ( $component eq $componentname )
-		{
-			$found = 1;
-			last;
-		}	
-	}
-	
-	if (!($found))
-	{
-		# This component can be ignored, if it exists in a version with extension "_pff" (this was renamed in file::get_sequence_for_file() )
-		my $ignore_this_component = 0;
-		my $origcomponentname = $componentname;
-		my $componentname = $componentname . "_pff";
-		
-		for ( my $j = 0; $j <= $#{$filesref}; $j++ )
-		{
-			$onefile = 	${$filesref}[$j];
-			$component = $onefile->{'componentname'};
-		
-			if ( $component eq $componentname )
-			{
-				$ignore_this_component = 1;
-				last;
-			}	
-		}
-		
-		if ( $ignore_this_component ) { return "IGNORE_COMP"; }
-		else { installer::exiter::exit_program("ERROR: Did not find component \"$origcomponentname\" in file collection", "get_file_component_directory"); }
-	}
+    foreach my $onefile (@$filesref)
+    {
+        if ($onefile->{'componentname'} eq $componentname)
+        {
+            return get_file_component_directory_for_file($onefile, $dirref);
+        }
+    }
+    
+    # This component can be ignored, if it exists in a version with
+    # extension "_pff" (this was renamed in file::get_sequence_for_file() )
+    my $ignore_this_component = 0;
+    my $origcomponentname = $componentname;
+    my $componentname_pff = $componentname . "_pff";
+        
+    foreach my $onefile (@$filesref)
+    {
+        if ($onefile->{'componentname'} eq $componentname_pff)
+        {
+            return "IGNORE_COMP";
+        }
+    }
+
+    installer::exiter::exit_program(
+        "ERROR: Did not find component \"$origcomponentname\" in file collection",
+        "get_file_component_directory");
+}
 
-	my $localstyles = "";
-	
-	if ( $onefile->{'Styles'} ) { $localstyles = $onefile->{'Styles'}; }
 
+
+
+sub get_file_component_directory_for_file ($$)
+{
+    my ($onefile, $dirref) = @_;
+
+	my $localstyles = $onefile->{'Styles'} // "";
+	
 	if ( $localstyles =~ /\bFONT\b/ )	# special handling for font files
 	{
 		return $installer::globals::fontsfolder;
@@ -124,44 +125,42 @@ sub get_file_component_directory
 	installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
 
 	$destination =~ s/\Q$installer::globals::separator\E\s*$//;
-	
+
 	# This path has to be defined in the directory collection at "HostName" 
-	
+
+    my $uniquedir = undef;
 	if ($destination eq "")		# files in the installation root
 	{
 		$uniquedir = "INSTALLLOCATION";
 	}		
 	else
 	{
-		$found = 0;
-	
-		for ( my $i = 0; $i <= $#{$dirref}; $i++ )
+		my $found = 0;
+        foreach my $directory (@$dirref)
 		{
-			$onedir = 	${$dirref}[$i];
-			$hostname = $onedir->{'HostName'};
-		
-			if ( $hostname eq $destination )
+			if ($directory->{'HostName'} eq $destination)
 			{
 				$found = 1;
+                $uniquedir = $directory->{'uniquename'};
 				last;
 			}	
 		}
 
-		if (!($found))
+		if ( ! $found)
 		{
-			installer::exiter::exit_program("ERROR: Did not find destination $destination in directory collection", "get_file_component_directory");
+			installer::exiter::exit_program(
+                "ERROR: Did not find destination $destination in directory collection",
+                "get_file_component_directory");
 		}
-	
-		$uniquedir = $onedir->{'uniquename'};
-		
+
 		if ( $uniquedir eq $installer::globals::officeinstalldirectory )
 		{
 			$uniquedir = "INSTALLLOCATION";		
 		}
 	}
-		
+
 	$onefile->{'uniquedirname'} = $uniquedir;		# saving it in the file collection
-	
+
 	return $uniquedir	
 }
 
@@ -226,7 +225,8 @@ sub get_file_component_attributes
 		$attributes = 0;	# Assembly files cannot run from source
 	}
 		
-	if (( $onefile->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ ) || ( $onefile->{'needs_user_registry_key'} ))
+	if ((defined $onefile->{'Dir'} && $onefile->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/)
+        || $onefile->{'needs_user_registry_key'})
 	{
 		$attributes = 4;	# Files in shellnew dir and in non advertised startmenu entries must have user registry key as KeyPath
 	}
@@ -320,113 +320,310 @@ sub get_component_condition
 # real filename!
 ####################################################################
 
-sub get_component_keypath
+sub get_component_keypath ($$)
 {
-	my ($componentname, $itemsref, $componentidkeypathhashref) = @_;
-
-	my $oneitem;
-	my $found = 0;
-	my $infoline = "";
+	my ($componentname, $itemsref) = @_;
 
-	for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
+	foreach my $oneitem (@$itemsref)
 	{
-		$oneitem = 	${$itemsref}[$i];
 		my $component = $oneitem->{'componentname'};
-		
+
+		if ( ! defined $component)
+        {
+            installer::scriptitems::print_script_item($oneitem);
+            installer::logger::PrintError("item in get_component_keypath has no 'componentname'\n");
+            return "";
+        }
 		if ( $component eq $componentname )
 		{
-			$found = 1;
-			last;
-		}
-	}
+            my $keypath = $oneitem->{'uniquename'};	# "uniquename", not "Name" 
 	
-	if (!($found))
-	{
-		installer::exiter::exit_program("ERROR: Did not find component in file/registry collection, function get_component_keypath", "get_component_keypath");
-	}
+            # Special handling for components in
+            # PREDEFINED_OSSHELLNEWDIR. These components need as
+            # KeyPath a RegistryItem in HKCU
+            if ($oneitem->{'userregkeypath'})
+            {
+                $keypath = $oneitem->{'userregkeypath'};
+            }
 
-	my $keypath = $oneitem->{'uniquename'};	# "uniquename", not "Name" 
+            # saving it in the file and registry collection
+            $oneitem->{'keypath'} = $keypath;
 	
-	# Special handling for updates from existing databases, because KeyPath must not change
-	if (( $installer::globals::updatedatabase ) && ( exists($componentidkeypathhashref->{$componentname}) ))
-	{
-		$keypath = $componentidkeypathhashref->{$componentname};
-		# -> check, if this is a valid key path?!
-		if ( $keypath ne $oneitem->{'uniquename'} )
-		{
-			# Warning: This keypath was changed because of info from old database
-			$infoline = "WARNING: The KeyPath for component \"$componentname\" was changed from \"$oneitem->{'uniquename'}\" to \"$keypath\" because of information from update database";
-			$installer::logger::Lang->print($infoline);
+            return $keypath
 		}
 	}
 	
-	# Special handling for components in PREDEFINED_OSSHELLNEWDIR. These components
-	# need as KeyPath a RegistryItem in HKCU
-	if ( $oneitem->{'userregkeypath'} ) { $keypath = $oneitem->{'userregkeypath'}; }
+    installer::exiter::exit_program(
+        "ERROR: Did not find component in file/registry collection, function get_component_keypath",
+        "get_component_keypath");
+}
 
-	# saving it in the file and registry collection
-	$oneitem->{'keypath'} = $keypath;
-	
-	return $keypath
+
+
+
+sub remove_ooversion_from_component_name($)
+{
+    my ($component_name) = @_;
+
+    $component_name =~ s/_openoffice\d+//;
+
+    return $component_name;
 }
 
-###################################################################
-# Creating the file Componen.idt dynamically
-# Content: 
-# Component ComponentId Directory_ Attributes Condition KeyPath
-###################################################################
 
-sub	create_component_table
+
+
+sub prepare_component_table_creation ($$$)
 {
-	my ($filesref, $registryref, $dirref, $allfilecomponentsref, $allregistrycomponents, $basedir, $componentidhashref, $componentidkeypathhashref, $allvariables) = @_;
+    my ($file_components, $registry_components, $variables) = @_;
 
-	my @componenttable = ();
+    if ($installer::globals::is_release)
+    {
+        my %source_component_data = ();
+        
+        # Collect the components that are used in the source release.
+        my $component_table = $installer::globals::source_msi->GetTable("Component");
+        foreach my $row (@{$component_table->GetAllRows()})
+        {
+            $source_component_data{$row->GetValue("Component")} = $row;
+        }
+
+        # Find source components that do not exist in the target components, ie have been removed.
+
+        # Process file components.
+        my @missing_source_component_names = ();
+        my %file_component_hash = map {$_ => 1} @$file_components;
+        foreach my $source_component_name (keys %source_component_data)
+        {
+            # In this loop we only process components for files and ignore those for registry entries.
+            next if $source_component_name =~ /^registry_/;
+            
+            if ( ! defined $file_component_hash{$source_component_name})
+            {
+                push @missing_source_component_names, [$source_component_name, $source_component_name];
+                $installer::logger::Info->printf("missing file component %s\n", $source_component_name);
+            }
+        }
+
+        # Process registry components.
+        my %registry_component_hash = map {$_ => 1} @$registry_components;
+        my %registry_component_hash_normalized = map {remove_ooversion_from_component_name($_) => $_} @$registry_components;
+        my %target_registry_component_translation = ();
+        foreach my $source_component_name (keys %source_component_data)
+        {
+            # In this loop we only process components for registry entries and ignore those for files.
+            next if $source_component_name !~ /^registry_/;
+            
+            if (defined $registry_component_hash{$source_component_name})
+            {
+                # Found the non-normalized name.
+            }
+            elsif (defined $registry_component_hash_normalized{
+                remove_ooversion_from_component_name($source_component_name)})
+            {
+                # Found the normalized name.
+                my $target_component_name = $registry_component_hash_normalized{
+                    remove_ooversion_from_component_name($source_component_name)};
+                $target_registry_component_translation{$target_component_name} = $source_component_name;
+                $installer::logger::Info->printf("found normalized component name %s\n", $source_component_name);
+                $installer::logger::Info->printf("    %s -> %s\n", $target_component_name, $source_component_name);
+            }
+            else
+            {
+                # Source component was not found.
+                push @missing_source_component_names, $source_component_name;
+                $installer::logger::Info->printf("missing component %s\n", $source_component_name);
+            }
+        }
+
+        if (scalar @missing_source_component_names > 0)
+        {
+            $installer::logger::Info->printf("Error: there are %d missing components\n",
+                scalar @missing_source_component_names);
+            return {};
+        }
+        else
+        {
+            return \%target_registry_component_translation;
+        }
+    }
 
-	my ($oneline, $infoline);
+    return {};
+}
 
-	installer::windows::idtglobal::write_idt_header(\@componenttable, "component");
 
-	# collect_layer_conditions();
 
 
-	# File components
+sub get_component_data ($$$$)
+{
+	my ($file_component_names,
+        $registry_component_names,
+        $files,
+        $registry_entries) = @_;
+
+    # When we are building a release then prepare building a patch by looking up some data
+    # from the previous release.
+    my %source_data = ();
+    if ($installer::globals::is_release)
+    {
+        my $source_component_table = $installer::globals::source_msi->GetTable("Component");
+        my $component_column_index = $source_component_table->GetColumnIndex("Component");
+        my $component_id_column_index = $source_component_table->GetColumnIndex("ComponentId");
+        my $key_path_column_index = $source_component_table->GetColumnIndex("KeyPath");
+        foreach my $source_row (@{$source_component_table->GetAllRows()})
+        {
+            my $component_name = $source_row->GetValue($component_column_index);
+            my $component_id = $source_row->GetValue($component_id_column_index);
+            my $key_path = $source_row->GetValue($key_path_column_index);
+
+            $source_data{$component_name} = {
+                'component_id' => $component_id,
+                'key_path' => $key_path
+            };
+        }
+    }
+
+    # Set up data for the target release.
+    # Use data from the source version where possible.
+    # Create missind data where necessary.
+
+    # Set up the target data with flags that remember whether a
+    # component contains files or registry entries.
+    my %target_data = ();
+    foreach my $name (@$file_component_names)
+    {
+        $target_data{$name} = {'is_file' => 1};
+    }
+    foreach my $name (@$registry_component_names)
+    {
+        $target_data{$name} = {'is_file' => 0};
+    }
+
+    # Add values for the ComponentId column.
+    $installer::logger::Lang->printf("preparing Component->ComponentId values\n");
+    foreach my $name (@$file_component_names,@$registry_component_names)
+    {
+        # Determine the component id.
+        my $guid = $installer::globals::is_release
+            ? $source_data{$name}->{'component_id'}
+            : undef;
+        if (defined $guid)
+        {
+            $installer::logger::Lang->printf("    reusing guid %s\n", $guid);
+        }
+        else
+        {
+            $guid = installer::windows::msiglobal::create_guid();
+            $installer::logger::Lang->printf("    creating new guid %s\n", $guid);
+        }
+        $target_data{$name}->{'component_id'} = $guid;
+    }
+
+    # Add values for the KeyPath column.
+    $installer::logger::Lang->printf("preparing Component->KeyPath values\n");
+    foreach my $name (@$file_component_names,@$registry_component_names)
+    {
+        # Determine the key path.
+        my $key_path = $installer::globals::is_release
+            ? $source_data{$name}->{'key_path'}
+            : undef;
+        if (defined $key_path)
+        {
+            $installer::logger::Lang->printf("    reusing key path %s\n", $key_path);
+        }
+        else
+        {
+            if ($target_data{$name}->{'is_file'})
+            {
+                $key_path = get_component_keypath($name, $files);
+            }
+            else
+            {
+                $key_path = get_component_keypath($name, $registry_entries); 
+            }
+        }
+        $target_data{$name}->{'key_path'} = $key_path;
+    }
 
-	for ( my $i = 0; $i <= $#{$allfilecomponentsref}; $i++ )
+    return \%target_data;
+}
+
+
+
+
+sub	create_component_table_data ($$$$$$)
+{
+	my ($filesref, $registryref, $dirref, $allfilecomponentsref, $allregistrycomponents, $allvariables) = @_;
+
+    my $target_data = get_component_data($allfilecomponentsref, $allregistrycomponents, $filesref, $registryref);
+    
+    my @table_data = ();
+
+	# File components
+	foreach my $name (@$allfilecomponentsref)
 	{
 		my %onecomponent = ();
 		
-		$onecomponent{'name'} = ${$allfilecomponentsref}[$i]; 
-		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'}, $componentidhashref); 
-		$onecomponent{'directory'} = get_file_component_directory($onecomponent{'name'}, $filesref, $dirref);
+		$onecomponent{'name'} = $name;
+		$onecomponent{'guid'} = $target_data->{$name}->{'component_id'};
+		$onecomponent{'directory'} = get_file_component_directory($name, $filesref, $dirref);
 		if ( $onecomponent{'directory'} eq "IGNORE_COMP" ) { next; }
-		$onecomponent{'attributes'} = get_file_component_attributes($onecomponent{'name'}, $filesref, $allvariables); 
-		$onecomponent{'condition'} = get_file_component_condition($onecomponent{'name'}, $filesref); 
-		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $filesref, $componentidkeypathhashref); 
+		$onecomponent{'attributes'} = get_file_component_attributes($name, $filesref, $allvariables); 
+		$onecomponent{'condition'} = get_file_component_condition($name, $filesref); 
+		$onecomponent{'keypath'} = $target_data->{$name}->{'key_path'};
 
-		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"  
-				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
-
-		push(@componenttable, $oneline);
+        push @table_data, \%onecomponent;
 	}	
 
 	# Registry components
-
-	for ( my $i = 0; $i <= $#{$allregistrycomponents}; $i++ )
+	foreach my $name (@$allregistrycomponents)
 	{
 		my %onecomponent = ();
-		
-		$onecomponent{'name'} = ${$allregistrycomponents}[$i]; 
-		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'}, $componentidhashref); 
+
+        $onecomponent{'name'} = $name;
+		$onecomponent{'guid'} = $target_data->{$name}->{'component_id'};
 		$onecomponent{'directory'} = get_registry_component_directory();
-		$onecomponent{'attributes'} = get_registry_component_attributes($onecomponent{'name'}, $allvariables); 
-		$onecomponent{'condition'} = get_component_condition($onecomponent{'name'}); 
-		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $registryref, $componentidkeypathhashref); 
+		$onecomponent{'attributes'} = get_registry_component_attributes($name, $allvariables); 
+		$onecomponent{'condition'} = get_component_condition($name); 
+		$onecomponent{'keypath'} = $target_data->{$name}->{'key_path'};
+
+		push(@table_data, \%onecomponent);
+	}
+
+    return \@table_data;
+}
+
+
 
-		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"  
-				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
 
+###################################################################
+# Creating the file Componen.idt dynamically
+# Content: 
+# Component ComponentId Directory_ Attributes Condition KeyPath
+###################################################################
+
+
+sub	create_component_table ($$)
+{
+	my ($table_data, $basedir) = @_;
+
+	my @componenttable = ();
+
+	my ($oneline, $infoline);
+
+	installer::windows::idtglobal::write_idt_header(\@componenttable, "component");
+
+	foreach my $item (@$table_data)
+	{
+		$oneline = sprintf("%s\t%s\t%s\t%s\t%s\t%s\n",
+            $item->{'name'},
+            $item->{'guid'},
+            $item->{'directory'},
+            $item->{'attributes'},
+            $item->{'condition'},
+            $item->{'keypath'});
 		push(@componenttable, $oneline);
-	}
+	}	
 
 	# Saving the file
 
@@ -436,6 +633,9 @@ sub	create_component_table
 	$installer::logger::Lang->print($infoline);
 }
 
+
+
+
 ####################################################################################
 # Returning a component for a scp module gid.
 # Pairs are saved in the files collector. 
@@ -518,4 +718,29 @@ sub set_component_in_environment_table
 	}
 }
 
+
+
+
+sub apply_component_translation ($@)
+{
+    my ($translation_map, @component_names) = @_;
+
+    my @translated_names = ();
+    foreach my $component_name (@component_names)
+    {
+        my $translated_name = $translation_map->{$component_name};
+        if (defined $translated_name)
+        {
+            push @translated_names, $translated_name;
+        }
+        else
+        {
+            push @translated_names, $component_name;
+        }
+    }
+
+    return @translated_names;
+}
+
+
 1;

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/directory.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/directory.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/directory.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/directory.pm Wed Dec 11 08:49:16 2013
@@ -29,6 +29,9 @@ use installer::globals;
 use installer::pathanalyzer;
 use installer::windows::idtglobal;
 use installer::windows::msiglobal;
+use installer::scriptitems;
+
+use strict;
 
 ##############################################################
 # Collecting all directory trees in global hash
@@ -73,12 +76,22 @@ sub overwrite_programfilesfolder
 	}
 }
 
-##############################################################
-# Maximum length of directory name is 72.
-# Taking care of underlines, which are the separator.
-##############################################################
 
-sub make_short_dir_version
+
+
+=head2 make_short_dir_version($longstring)
+
+    Transform the given string into one that is at most 70 characters long.
+    That is done in two steps:
+    - Cut all parts separated by '_' or '-' down to a length of 5.
+    - Cut down the result to a length of 60 and fill it up to length 70
+      with the MD5 checksum.
+
+    This transform always returns the same result for the same string.
+    There is no counter and reference to a global set of names to make the string unique.
+    
+=cut
+sub make_short_dir_version ($)
 {
 	my ($longstring) = @_;
 	
@@ -90,29 +103,24 @@ sub make_short_dir_version
 	# Splitting the string at each "underline" and allowing only $length characters per directory name.
 	# Checking also uniqueness and length.
 	
-	my $stringarray = installer::converter::convert_stringlist_into_array_without_newline(\$longstring, "_");
-	
-	foreach my $onestring ( @{$stringarray} )
+	my @outer_parts = split(/_/, $longstring);
+	foreach my $onestring (@outer_parts)
 	{
 		my $partstring = "";
 		
 		if ( $onestring =~ /\-/ )
 		{
-			my $localstringarray = installer::converter::convert_stringlist_into_array_without_newline(\$onestring, "-");
-			foreach my $onelocalstring ( @{$localstringarray} )
-			{
-				if ( length($onelocalstring) > $length ) { $onelocalstring = substr($onelocalstring, 0, $length); }
-				$partstring = $partstring . "-" . $onelocalstring;
-			}
+			my @inner_parts = split(/-/, $onestring);
+            @inner_parts = map {substr($_,0,$length)} @inner_parts;
+            $partstring = join("-", @inner_parts);
 			$partstring =~ s/^\s*\-//;
 		}
 		else
 		{
-			if ( length($onestring) > $length ) { $partstring = substr($onestring, 0, $length); }
-			else { $partstring = $onestring; }
+			$partstring = substr($onestring, 0, $length);
 		}
 
-		$shortstring = $shortstring . "_" . $partstring;
+		$shortstring .= "_" . $partstring;
 	}
 
 	$shortstring =~ s/^\s*\_//;
@@ -120,184 +128,311 @@ sub make_short_dir_version
 	# Setting unique ID to each directory
 	# No counter allowed, process must be absolute reproducable due to patch creation process.
 	
-	# chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`);  # Very, very slow
-	# my $subid = substr($id, 0, 9); # taking only the first 9 digits
-
 	my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits
-
-	if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }
-
-	$shortstring = $shortstring . "_" . $subid;
+	$shortstring = substr($shortstring, 0, $cutlength) . "_" . $subid;
 
 	return $shortstring;
 }
 
-##############################################################
-# Adding unique directory names to the directory collection
-##############################################################
 
-sub create_unique_directorynames
-{
-	my ($directoryref, $allvariables) = @_;
 
-	$installer::globals::officeinstalldirectoryset = 0;
 
-	my %completedirhashstep1 = ();
-	my %shortdirhash = ();
-	my %shortdirhashreverse = ();
-	my $infoline = "";
-	my $errorcount = 0;
+=head2 get_unique_name ($hostname, $unique_map, $shortdirhash, $shortdirhashreverse)
 
-	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
-	{
-		my $onedir = ${$directoryref}[$i];
-		my $uniquename = $onedir->{'HostName'};
+    Return a long and a short unique name for the given $hostname.
+    Despite the function name and unlike the generation of unique
+    names for files, the returned names are not really unique.  Quite
+    the opposite.  The returned names are quaranteed to return the
+    same result for the same input.
+
+    The returned short name has at most length 70.
+    
+=cut
+sub get_unique_name ($$)
+{
+    my ($hostname, $hostnamehash) = @_;
+
+    # Make sure that we where not called for this hostname before.  Otherwise the other test would be triggered.
+    if (defined $hostnamehash->{$hostname})
+    {
+        installer::exiter::exit_program(
+            "ERROR: get_unique_name was already called for hostname ".$hostname,
+            "get_unique_name");
+    }
+    $hostnamehash->{$hostname} = 1;
+    
+    my $uniquename = $hostname;
+
+    $uniquename =~ s/^\s*//g;				# removing beginning white spaces
+    $uniquename =~ s/\s*$//g;				# removing ending white spaces
+    $uniquename =~ s/\s//g;					# removing white spaces
+    $uniquename =~ s/\_//g;					# removing existing underlines
+    $uniquename =~ s/\.//g;					# removing dots in directoryname
+    $uniquename =~ s/OpenOffice/OO/g;
+    
+    $uniquename =~ s/\Q$installer::globals::separator\E/\_/g;	# replacing slash and backslash with underline
+    
+    $uniquename =~ s/_registry/_rgy/g;
+    $uniquename =~ s/_registration/_rgn/g;
+    $uniquename =~ s/_extension/_ext/g;
+    $uniquename =~ s/_frame/_frm/g;
+    $uniquename =~ s/_table/_tbl/g;
+    $uniquename =~ s/_chart/_crt/g;
+
+    my $short_uniquename = make_short_dir_version($uniquename);
+
+    return ($uniquename, $short_uniquename);
+}
 
-		my $styles = "";
-		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
 
-		$uniquename =~ s/^\s*//g;				# removing beginning white spaces
-		$uniquename =~ s/\s*$//g;				# removing ending white spaces
-		$uniquename =~ s/\s//g;					# removing white spaces
-		$uniquename =~ s/\_//g;					# removing existing underlines
-		$uniquename =~ s/\.//g;					# removing dots in directoryname
-		$uniquename =~ s/OpenOffice/OO/g;
 
-		$uniquename =~ s/\Q$installer::globals::separator\E/\_/g;	# replacing slash and backslash with underline
 
-		$uniquename =~ s/_registry/_rgy/g;
-		$uniquename =~ s/_registration/_rgn/g;
-		$uniquename =~ s/_extension/_ext/g;
-		$uniquename =~ s/_frame/_frm/g;
-		$uniquename =~ s/_table/_tbl/g;
-		$uniquename =~ s/_chart/_crt/g;
+=head2 check_unique_directorynames($directories)
+
+    The one really important check is made in get_unique_name().  It
+    checks that get_unique_name() is not called twice for the same
+    directory host name.  The tests in this function contain the
+    legacy tests that basically only check if there where a collision
+    of the partial MD5 sum that is used to make the short unique names
+    unique.
+
+    The maps $unique_map, $shortdirhash, $shortdirhashreverse are used
+    only to check that _different_ input names are mapped to different
+    results.  They are not used to influence the result.  That assumes
+    that this function is called only once for every directory
+    hostname.
+=cut
+sub check_unique_directorynames ($)
+{
+    my ($directories) = @_;
 
-		# The names after this small changes must still be unique!
-		if ( exists($completedirhashstep1{$uniquename}) ) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 1): \"$uniquename\".", "create_unique_directorynames"); }
-		$completedirhashstep1{$uniquename} = 1;
+    my %completedirhashstep1 = ();
+	my %shortdirhash = ();
+	my %shortdirhashreverse = ();
 
-		# Starting to make unique name for the parent and its directory
-		my $originaluniquename = $uniquename;
+    # Check unique name of directories.
+    foreach my $directory (@$directories)
+    {
+        my ($long_uniquename, $short_uniquename) = ($directory->{'long_uniquename'}, $directory->{'uniquename'});
+        
+        # The names after this small changes must still be unique!
+        if (exists($completedirhashstep1{$long_uniquename}))
+        {
+            installer::exiter::exit_program(
+                sprintf("ERROR: Unallowed modification of directory name, not unique (step 1): \"%s\".",
+                    $short_uniquename),
+                "check_unique_directorynames");
+        }
+        $completedirhashstep1{$long_uniquename} = 1;
+
+
+        # Checking if the same directory already exists, but has another short version.
+        if (exists($shortdirhash{$long_uniquename})
+            && ( $shortdirhash{$long_uniquename} ne $short_uniquename ))
+        {
+            installer::exiter::exit_program(
+                sprintf(
+                    "ERROR: Unallowed modification of directory name, not unique (step 2A): \"%s\".",
+                    $short_uniquename),
+                "check_unique_directorynames");
+        }
+        $shortdirhash{$long_uniquename} = $short_uniquename;
+
+        # Also checking vice versa
+        # Checking if the same short directory already exists, but has another long version.
+        if (exists($shortdirhashreverse{$short_uniquename})
+            && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename ))
+        {
+            installer::exiter::exit_program(
+                sprintf(
+                    "ERROR: Unallowed modification of directory name, not unique (step 2B): \"%s\".",
+                    $short_uniquename),
+                "check_unique_directorynames");
+        }
+        $shortdirhashreverse{$short_uniquename} = $long_uniquename;
+    }
+
+    # Check unique name of parents
+    foreach my $directory (@$directories)
+    {
+        my ($long_uniquename, $short_uniquename)
+            = ($directory->{'long_uniqueparentname'}, $directory->{'uniqueparentname'});
+
+        # Again checking if the same directory already exists, but has another short version.
+        if (exists($shortdirhash{$long_uniquename})
+            && ( $shortdirhash{$long_uniquename} ne $short_uniquename ))
+        {
+            installer::exiter::exit_program(
+                sprintf(
+                    "ERROR: Unallowed modification of directory name, not unique (step 3A): \"%s\".",
+                    $short_uniquename),
+                "check_unique_directorynames");
+        }
+        $shortdirhash{$long_uniquename} = $short_uniquename;
+
+        # Also checking vice versa
+        # Checking if the same short directory already exists, but has another long version.
+        if (exists($shortdirhashreverse{$short_uniquename})
+            && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename ))
+        {
+            installer::exiter::exit_program(
+                sprintf(
+                    "ERROR: Unallowed modification of directory name, not unique (step 3B): \"%s\".",
+                    $short_uniquename),
+                "check_unique_directorynames");
+        }
+        $shortdirhashreverse{$short_uniquename} = $long_uniquename;
+    }
+}
 
-		$uniquename = make_short_dir_version($uniquename);
 
-		# Checking if the same directory already exists, but has another short version.
-		if (( exists($shortdirhash{$originaluniquename}) ) && ( $shortdirhash{$originaluniquename} ne $uniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2A): \"$uniquename\".", "create_unique_directorynames"); }
 
-		# Also checking vice versa
-		# Checking if the same short directory already exists, but has another long version.
-		if (( exists($shortdirhashreverse{$uniquename}) ) && ( $shortdirhashreverse{$uniquename} ne $originaluniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2B): \"$uniquename\".", "create_unique_directorynames"); }
 
-		# Creating assignment from long to short directory names
-		$shortdirhash{$originaluniquename} = $uniquename;
-		$shortdirhashreverse{$uniquename} = $originaluniquename;
+sub get_unique_parent_name ($$)
+{
+    my ($uniqueparentname, $styles) = @_;
+
+    my $keepparent = 1;
+
+    if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ )	# the underline is now the separator
+    {
+        $uniqueparentname = $1;
+        $keepparent = 0;
+    }
+    else
+    {
+        $uniqueparentname = $installer::globals::programfilesfolder;
+        $keepparent = 1;
+    }
+
+    if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
+    {
+        $uniqueparentname = $installer::globals::programfilesfolder;
+        $keepparent = 1;
+    }
+    if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
+    {
+        $uniqueparentname = $installer::globals::commonfilesfolder;
+        $keepparent = 1;
+    }
+    if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
+    {
+        $uniqueparentname = $installer::globals::commonappdatafolder;
+        $keepparent = 1;
+    }
+    if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
+    {
+        $uniqueparentname = $installer::globals::localappdatafolder;
+        $keepparent = 1;
+    }
+    
+    if ( $styles =~ /\bSHAREPOINTPATH\b/ )
+    {
+        $uniqueparentname = "SHAREPOINTPATH";
+        $installer::globals::usesharepointpath = 1;
+        $keepparent = 1;
+    }
+
+    # also setting short directory name for the parent
+		
+    my $originaluniqueparentname = $uniqueparentname;
+
+    if ( ! $keepparent )
+    {
+        $uniqueparentname = make_short_dir_version($uniqueparentname);
+    }
 
-		# Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).
+    return ($originaluniqueparentname, $uniqueparentname);
+}
 
-		my $uniqueparentname = $originaluniquename;
-		my $keepparent = 1;
 
-		if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ )	# the underline is now the separator
-		{
-			$uniqueparentname = $1;
-			$keepparent = 0;
-		}
-		else
-		{
-			$uniqueparentname = $installer::globals::programfilesfolder;
-			$keepparent = 1;
-		}
 
-		if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
-		{
-			$uniqueparentname = $installer::globals::programfilesfolder;
-			$keepparent = 1;
-		}
-		if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
-		{
-			$uniqueparentname = $installer::globals::commonfilesfolder;
-			$keepparent = 1;
-		}
-		if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
-		{
-			$uniqueparentname = $installer::globals::commonappdatafolder;
-			$keepparent = 1;
-		}
-		if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
-		{
-			$uniqueparentname = $installer::globals::localappdatafolder;
-			$keepparent = 1;
-		}
 
-		if ( $styles =~ /\bSHAREPOINTPATH\b/ )
-		{
-			$uniqueparentname = "SHAREPOINTPATH";
-			$installer::globals::usesharepointpath = 1;
-			$keepparent = 1;
-		}
+##############################################################
+# Adding unique directory names to the directory collection
+##############################################################
 
-		# also setting short directory name for the parent
-		
-		my $originaluniqueparentname = $uniqueparentname;
+sub create_unique_directorynames ($)
+{
+	my ($directories) = @_;
 
-		if ( ! $keepparent )
-		{
-			$uniqueparentname = make_short_dir_version($uniqueparentname);
-		}
+	$installer::globals::officeinstalldirectoryset = 0;
+
+    my %hostnamehash = ();
+	my $infoline = "";
+	my $errorcount = 0;
+
+	foreach my $directory (@$directories)
+	{
+        next if defined $directory->{'uniquename'};
+
+        my $styles = $directory->{'Styles'} // "";
 
-		# Again checking if the same directory already exists, but has another short version.
-		if (( exists($shortdirhash{$originaluniqueparentname}) ) && ( $shortdirhash{$originaluniqueparentname} ne $uniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3A): \"$uniqueparentname\".", "create_unique_directorynames"); }
+		my ($originaluniquename, $uniquename) = get_unique_name(
+            $directory->{'HostName'},
+            \%hostnamehash);
 
-		# Also checking vice versa
-		# Checking if the same short directory already exists, but has another long version.
-		if (( exists($shortdirhashreverse{$uniqueparentname}) ) && ( $shortdirhashreverse{$uniqueparentname} ne $originaluniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3B): \"$uniqueparentname\".", "create_unique_directorynames"); }
+		my ($originaluniqueparentname, $uniqueparentname) = get_unique_parent_name(
+            $originaluniquename,
+            $styles);
 
-		$shortdirhash{$originaluniqueparentname} = $uniqueparentname;
-		$shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
 		
 		# Hyphen not allowed in database
 		$uniquename =~ s/\-/\_/g;			# making "-" to "_"
 		$uniqueparentname =~ s/\-/\_/g;		# making "-" to "_"
 		
 		# And finally setting the values for the directories
-		$onedir->{'uniquename'} = $uniquename;
-		$onedir->{'uniqueparentname'} = $uniqueparentname;
-
+		$directory->{'uniquename'} = $uniquename;
+		$directory->{'uniqueparentname'} = $uniqueparentname;
+		$directory->{'long_uniquename'} = $originaluniquename;
+		$directory->{'long_uniqueparentname'} = $originaluniqueparentname;
+    }
+
+    # Find the installation directory.
+    foreach my $directory (@$directories)
+    {
+        next unless defined $directory->{'Styles'};
+        
 		# setting the installlocation directory
-		if ( $styles =~ /\bISINSTALLLOCATION\b/ )
-		{
-			if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
-			$installer::globals::installlocationdirectory = $uniquename;
-			$installer::globals::installlocationdirectoryset = 1;
-		}
-		
-		# setting the sundirectory
-		if ( $styles =~ /\bSUNDIRECTORY\b/ )
-		{
-			if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); }
-			$installer::globals::vendordirectory = $uniquename;
-			$installer::globals::vendordirectoryset = 1;
-		}
-	}	
+		next unless $directory->{'Styles'} =~ /\bISINSTALLLOCATION\b/;
+
+        if ( $installer::globals::installlocationdirectoryset )
+        {
+            installer::exiter::exit_program(
+                sprintf(
+                    "ERROR: Directory with flag ISINSTALLLOCATION alread set: \"%s\".",
+                    $installer::globals::installlocationdirectory),
+                "create_unique_directorynames");
+        }
+
+        $installer::globals::installlocationdirectory = $directory->{'uniquename'};
+        $installer::globals::installlocationdirectoryset = 1;
+    }
 }
 
+
+
+
 #####################################################
 # Adding ":." to selected default directory names
 #####################################################
 
-sub check_sourcedir_addon
+sub update_defaultdir ($$)
 {
 	my ( $onedir, $allvariableshashref ) = @_;
 	
-	if (($installer::globals::addchildprojects) ||
-		($installer::globals::patch) ||
-		($installer::globals::languagepack) || 
-		($allvariableshashref->{'CHANGETARGETDIR'}))
+	if ($installer::globals::addchildprojects
+        || $installer::globals::patch
+        || $installer::globals::languagepack
+        || $allvariableshashref->{'CHANGETARGETDIR'})
 	{
 		my $sourcediraddon = "\:\.";
-		$onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
+		return $onedir->{'defaultdir'} . $sourcediraddon;
 	}			
-	
+	else
+    {
+        return $onedir->{'defaultdir'};
+    }
 }
 
 #####################################################
@@ -309,7 +444,12 @@ sub set_installlocation_directory
 {
 	my ( $directoryref, $allvariableshashref ) = @_;
 	
-	if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
+	if ( ! $installer::globals::installlocationdirectoryset )
+    {
+        installer::exiter::exit_program(
+            "ERROR: Directory with flag ISINSTALLLOCATION not set!",
+            "set_installlocation_directory");
+    }
 	
 	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
 	{
@@ -318,12 +458,12 @@ sub set_installlocation_directory
 		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
 		{
 			$onedir->{'uniquename'} = "INSTALLLOCATION";
-			check_sourcedir_addon($onedir, $allvariableshashref);
+			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);
 		}
 		
 		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
 		{
-			check_sourcedir_addon($onedir, $allvariableshashref);			
+			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);			
 		}
 		
 		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
@@ -348,13 +488,38 @@ sub get_last_directory_name
 	}
 }
 
+sub setup_global_font_directory_name ($)
+{
+	my ($directories) = @_;
+
+	foreach my $directory (@$directories)
+	{		
+        next unless defined $directory->{'Dir'};
+        next unless defined $directory->{'defaultdir'};
+
+        next if $directory->{'Dir'} ne "PREDEFINED_OSSYSTEMFONTDIR";
+        next if $directory->{'defaultdir'} ne $installer::globals::fontsdirhostname;
+
+        $installer::globals::fontsdirname = $installer::globals::fontsdirhostname;
+        $installer::globals::fontsdirparent = $directory->{'uniqueparentname'};
+
+        $installer::logger::Info->printf("%s, fdhn %s, dd %s, ipn %s, HN %s\n",
+            "PREDEFINED_OSSYSTEMFONTDIR",
+            $installer::globals::fontsdirhostname,
+            $directory->{'defaultdir'},
+            $directory->{'uniqueparentname'},
+            $directory->{'HostName'});
+        installer::scriptitems::print_script_item($directory);
+	}
+}
+
 #####################################################
 # Creating the defaultdir for the file Director.idt
 #####################################################
 
-sub create_defaultdir_directorynames
+sub create_defaultdir_directorynames ($)
 {
-	my ($directoryref, $shortdirnamehashref) = @_;
+	my ($directoryref) = @_;
 
 	my @shortnames = ();
 	if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
@@ -390,18 +555,6 @@ sub create_defaultdir_directorynames
 		}
 
 		$onedir->{'defaultdir'} = $defaultdir;
-
-		my $fontdir = "";
-		if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
-
-		my $fontdefaultdir = "";
-		if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
-
-		if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname ))
-		{
-			$installer::globals::fontsdirname = $onedir->{'defaultdir'};
-			$installer::globals::fontsdirparent = $onedir->{'uniqueparentname'};
-		}
 	}
 }
 
@@ -409,23 +562,28 @@ sub create_defaultdir_directorynames
 # Fill content into the directory table
 ###############################################
 
-sub create_directorytable_from_collection
+sub create_directorytable_from_collection ($$)
 {
 	my ($directorytableref, $directoryref) = @_;
 	
-	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
+	foreach my $onedir (@$directoryref)
 	{
-		my $onedir = ${$directoryref}[$i];
-		my $hostname = $onedir->{'HostName'};
-		my $dir = "";
-		
-		if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
-		
-		if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; }	# removing files from root directory
-		
-		my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
+        # Remove entries for special directories.
+		if (defined $onedir->{'HostName'}
+            && $onedir->{'HostName'} eq ""
+            && defined $onedir->{'Dir'}
+            && $onedir->{'Dir'} eq "PREDEFINED_PROGDIR")
+        {
+            next;
+        }
+        
+		my $oneline = sprintf(
+            "%s\t%s\t%s\n",
+            $onedir->{'uniquename'},
+            $onedir->{'uniqueparentname'},
+            $onedir->{'defaultdir'});
 
-		push(@{$directorytableref}, $oneline);
+		push @{$directorytableref}, $oneline;
 	}
 }
 
@@ -433,19 +591,10 @@ sub create_directorytable_from_collectio
 # Defining the root installation structure
 ###############################################
 
-sub add_root_directories
+sub process_root_directories ($$)
 {
-	my ($directorytableref, $allvariableshashref) = @_;
+	my ($allvariableshashref, $functor) = @_;
 	
-#	my $sourcediraddon = "";
-#	if (($installer::globals::addchildprojects) ||
-#		($installer::globals::patch) ||
-#		($installer::globals::languagepack) || 
-#		($allvariableshashref->{'CHANGETARGETDIR'}))
-#	{
-#		$sourcediraddon = "\:\.";
-#	}
-
 	my $oneline = "";
 
 	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
@@ -473,76 +622,188 @@ sub add_root_directories
 			$realproductkey =~ s/\ /\_/g; 
 		}
 		
-		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir");		# third parameter not used
+		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir", undef);
 		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
-			
-		$oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
-		push(@{$directorytableref}, $oneline);
-	}
-
-	$oneline = "TARGETDIR\t\tSourceDir\n";
-	push(@{$directorytableref}, $oneline);
-
-	$oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
-
-	$oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);			
-
-	$oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
 
-	$oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
-
-	$oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
-
-	$oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
-
-	$oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
+        &$functor(
+            $installer::globals::officemenufolder,
+            $installer::globals::programmenufolder,
+            $shortproductkey . "|". $realproductkey);
+	}
 
-	$oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
+	&$functor("TARGETDIR", "", "SourceDir");
+	&$functor($installer::globals::programfilesfolder, "TARGETDIR", ".");
+    &$functor($installer::globals::programmenufolder, "TARGETDIR", ".");
+    &$functor($installer::globals::startupfolder, "TARGETDIR", ".");
+	&$functor($installer::globals::desktopfolder, "TARGETDIR", ".");
+	&$functor($installer::globals::startmenufolder, "TARGETDIR", ".");
+	&$functor($installer::globals::commonfilesfolder, "TARGETDIR", ".");
+	&$functor($installer::globals::commonappdatafolder, "TARGETDIR", ".");
+	&$functor($installer::globals::localappdatafolder, "TARGETDIR", ".");
 		
 	if ( $installer::globals::usesharepointpath )
 	{
-		$oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
-		push(@{$directorytableref}, $oneline);
+		&$functor("SHAREPOINTPATH", "TARGETDIR", ".");
 	}
 
-	$oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n";
-	push(@{$directorytableref}, $oneline);
+	&$functor($installer::globals::systemfolder, "TARGETDIR", ".");
 
 	my $localtemplatefoldername = $installer::globals::templatefoldername;
 	my $directorytableentry = $localtemplatefoldername;
 	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
-	if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
-	$oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
-	push(@{$directorytableref}, $oneline);
+	if ( $shorttemplatefoldername ne $localtemplatefoldername )
+    {
+        $directorytableentry = $shorttemplatefoldername . "|" . $localtemplatefoldername;
+    }
+	&$functor($installer::globals::templatefolder, "TARGETDIR", $directorytableentry);
 
 	if ( $installer::globals::fontsdirname )
 	{
-		$oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
+		&$functor(
+             $installer::globals::fontsfolder,
+             $installer::globals::fontsdirparent,
+             $installer::globals::fontsfoldername . ":" . $installer::globals::fontsdirname);
 	}
 	else
 	{
-		$oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
+		&$functor(
+             $installer::globals::fontsfolder,
+             "TARGETDIR",
+             $installer::globals::fontsfoldername);
 	}
+}
+
+
 
-	push(@{$directorytableref}, $oneline);
 
+sub find_missing_directories ($$)
+{
+    my ($directories, $allvariableshashref) = @_;
+
+    # Set up the list of target directories.
+    my %target_directories = map {$_->{'uniquename'} => 1} @$directories;
+    # Add special directories.
+    process_root_directories(
+        $allvariableshashref,
+        sub($$$){
+            my ($uniquename, $parentname, $defaultdir) = @_;
+            $target_directories{$uniquename} = 1;
+        }
+    );
+
+    # Set up the list of source directories.
+    my $source_directory_map = $installer::globals::source_msi->GetDirectoryMap();
+    my $source_file_map = $installer::globals::source_msi->GetFileMap();
+    my %source_directories = map {$_->{'unique_name'} => $_} values %$source_directory_map;
+
+    # Find the missing source directories.
+    my @missing_directories = ();
+    foreach my $source_uniquename (keys %source_directories)
+    {
+        if ( ! $target_directories{$source_uniquename})
+        {
+            push @missing_directories, $source_directories{$source_uniquename};
+        }
+    }
+
+    # Report the missing directories.
+    $installer::logger::Info->printf("found %d missing directories\n", scalar @missing_directories);
+    my $index = 0;
+    foreach my $directory_item (@missing_directories)
+    {
+        # Print information about the directory.
+        $installer::logger::Info->printf("missing directory %d: %s\n",
+            ++$index,
+            $directory_item->{'full_target_long_name'});
+        while (my($key,$value) = each %$directory_item)
+        {
+            $installer::logger::Info->printf("    %s -> %s\n", $key, $value);
+        }
+
+        # Print the referencing files.
+        my @filenames = ();
+        while (my ($key,$value) = each %$source_file_map)
+        {
+            if ($value->{'directory'}->{'unique_name'} eq $directory_item->{'unique_name'})
+            {
+                push @filenames, $key;
+            }
+        }
+        $installer::logger::Info->printf("  referencing files are %s\n", join(", ", @filenames));        
+    }
+
+    foreach my $directory (@$directories)
+    {
+        $installer::logger::Lang->printf("target directory %s -> HN %s\n",
+            $directory->{'uniquename'},
+            $directory->{'HostName'});
+        installer::scriptitems::print_script_item($directory);
+    }
+
+    # Setup a map of directory uniquenames to verify that the new
+    # entries don't use unique names that are already in use.
+    my %unique_names = map {$_->{'uniquename'} => $_} @$directories;
+
+    # Create script items for the missing directories.
+    my @new_source_directories = ();
+    foreach my $source_directory_item (@missing_directories)
+    {
+        my $new_directory_item = {
+            'uniquename' => $source_directory_item->{'unique_name'},
+            'uniqueparentname' => $source_directory_item->{'parent'},
+            'defaultdir' => $source_directory_item->{'default_dir'},
+            'HostName' => $source_directory_item->{'full_target_long_name'},
+            'componentname' => $source_directory_item->{'component_name'},
+        };
+
+        if (defined $unique_names{$new_directory_item->{'uniquename'}})
+        {
+            installer::logger::PrintError("newly created directory entry collides with existing directory");
+            last;
+        }
+
+        push @new_source_directories, $new_directory_item;
+    }
+
+    return @new_source_directories;
 }
 
+
+
+
+sub prepare_directory_table_creation ($$)
+{
+	my ($directories, $allvariableshashref) = @_;
+
+    foreach my $directory (@$directories)
+    {
+        delete $directory->{'uniquename'};
+    }
+
+	overwrite_programfilesfolder($allvariableshashref);
+	create_unique_directorynames($directories);
+    check_unique_directorynames($directories);
+	create_defaultdir_directorynames($directories);	# only destdir!
+    setup_global_font_directory_name($directories);
+	set_installlocation_directory($directories, $allvariableshashref);
+
+    if ($installer::globals::is_release)
+    {
+        my @new_directories = find_missing_directories($directories, $allvariableshashref);
+        push @$directories, @new_directories;
+    }
+}
+
+
+
+
 ###############################################
 # Creating the file Director.idt dynamically
 ###############################################
 
-sub create_directory_table
+sub create_directory_table ($$$)
 {
-	my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
+	my ($directoryref, $basedir, $allvariableshashref) = @_;
 
 	# Structure of the directory table:
 	# Directory Directory_Parent DefaultDir
@@ -555,18 +816,17 @@ sub create_directory_table
 	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");
 
 	my @directorytable = ();
-	my $infoline;
-	
-	overwrite_programfilesfolder($allvariableshashref);
-	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); }
-	create_unique_directorynames($directoryref, $allvariableshashref);
-	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); }
-	create_defaultdir_directorynames($directoryref, $shortdirnamehashref);	# only destdir!
-	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); }
-	set_installlocation_directory($directoryref, $allvariableshashref);
-	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); }
 	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
-	add_root_directories(\@directorytable, $allvariableshashref);
+
+    # Add entries for the root directories (and a few special directories like that for fonts).
+    process_root_directories(
+        $allvariableshashref,
+        sub($$$){
+            push(@directorytable, join("\t", @_)."\n");
+        }
+    );
+
+    # Add entries for the non-root directories.
 	create_directorytable_from_collection(\@directorytable, $directoryref);
 
 	# Saving the file
@@ -578,4 +838,5 @@ sub create_directory_table
 	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
 }
 
+
 1;

Modified: openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/featurecomponent.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/featurecomponent.pm?rev=1550072&r1=1550071&r2=1550072&view=diff
==============================================================================
--- openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/featurecomponent.pm (original)
+++ openoffice/branches/rejuvenate01/main/solenv/bin/modules/installer/windows/featurecomponent.pm Wed Dec 11 08:49:16 2013
@@ -30,37 +30,46 @@ use installer::files;
 use installer::globals;
 use installer::windows::idtglobal;
 
+use strict;
+
+
 #################################################################################
 # Collecting all pairs of features and components from the files collector
 #################################################################################
 
-sub create_featurecomponent_table_from_files_collector
+sub create_featurecomponent_table_from_files_collector ($$)
 {
 	my ($featurecomponenttableref, $filesref) = @_;
 
-	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
+	foreach my $onefile (@$filesref)
 	{
-		my $onefile = ${$filesref}[$i];
-		
 		my $filecomponent = $onefile->{'componentname'};
 		my $filemodules = $onefile->{'modules'};
 
 		if ( $filecomponent eq "" ) 
 		{
-			installer::exiter::exit_program("ERROR: No component defined for file $onefile->{'Name'}", "create_featurecomponent_table_from_files_collector");
-		}
-		if ( $filemodules eq "" ) 
-		{
-			installer::exiter::exit_program("ERROR: No modules found for file $onefile->{'Name'}", "create_featurecomponent_table_from_files_collector");
+			installer::exiter::exit_program(
+                sprintf("ERROR: No component defined for file %s", $onefile->{'Name'}),
+                "create_featurecomponent_table_from_files_collector");
+		}
+        if ( ! defined $filemodules)
+        {
+            # Temporary for files created from source installation set.
+            die;
+        }
+		if ($filemodules eq "") 
+		{
+			installer::exiter::exit_program(
+                sprintf("ERROR: No modules found for file %s", $onefile->{'Name'}),
+                "create_featurecomponent_table_from_files_collector");
 		}
 
 		my $filemodulesarrayref = installer::converter::convert_stringlist_into_array(\$filemodules, ",");
 
-		for ( my $j = 0; $j <= $#{$filemodulesarrayref}; $j++ )
+		foreach my $onemodule (@$filemodulesarrayref)
 		{
 			my %featurecomponent = ();
 			
-			my $onemodule = ${$filemodulesarrayref}[$j];
 			$onemodule =~ s/\s*$//;
 			$featurecomponent{'Feature'} = $onemodule;
 			$featurecomponent{'Component'} = $filecomponent;
@@ -70,7 +79,7 @@ sub create_featurecomponent_table_from_f
 
 			installer::windows::idtglobal::shorten_feature_gid(\$featurecomponent{'Feature'});
 			
-			$oneline = "$featurecomponent{'Feature'}\t$featurecomponent{'Component'}\n";
+			my $oneline = "$featurecomponent{'Feature'}\t$featurecomponent{'Component'}\n";
 			
 			# control of uniqueness
 			
@@ -82,56 +91,66 @@ sub create_featurecomponent_table_from_f
 	}			
 }
 
-#################################################################################
-# Collecting all pairs of features and components from the registry collector
-#################################################################################
 
-sub create_featurecomponent_table_from_registry_collector
+
+
+=head2 create_featurecomponent_table_from_registry_collector ($featurecomponenttableref, $registryref)
+
+    Add entries for the FeatureComponent table for components that contain registry entries.
+
+=cut
+sub create_featurecomponent_table_from_registry_collector ($$)
 {
 	my ($featurecomponenttableref, $registryref) = @_;
 
-	for ( my $i = 0; $i <= $#{$registryref}; $i++ )
+    my $replacement_count = 0;
+    my $unique_count = 0;
+	foreach my $oneregistry (@$registryref)
 	{
-		my $oneregistry = ${$registryref}[$i];
-		
-		my $registrycomponent = $oneregistry->{'componentname'};
-		my $registrymodule = $oneregistry->{'ModuleID'};
-
-		if ( $registrycomponent eq "" ) 
+		my $component_name = $oneregistry->{'componentname'};
+		if ($component_name eq "") 
 		{
-			installer::exiter::exit_program("ERROR: No component defined for registry $oneregistry->{'gid'}", "create_featurecomponent_table_from_registry_collector");
+			installer::exiter::exit_program(
+                sprintf("ERROR: No component defined for registry %s", $oneregistry->{'gid'}),
+                "create_featurecomponent_table_from_registry_collector");
 		}
-		if ( $registrymodule eq "" ) 
+
+		my $feature_name = $oneregistry->{'ModuleID'};
+		if ($feature_name eq "") 
 		{
-			installer::exiter::exit_program("ERROR: No modules found for registry $oneregistry->{'gid'}", "create_featurecomponent_table_from_registry_collector");
+			installer::exiter::exit_program(
+                sprintf("ERROR: No modules found for registry %s", $oneregistry->{'gid'}),
+                "create_featurecomponent_table_from_registry_collector");
 		}
 
-		my %featurecomponent = ();
-			
-		$featurecomponent{'Feature'} = $registrymodule;
-		$featurecomponent{'Component'} = $registrycomponent;
-		
 		# Attention: Features are renamed, because the maximum length is 38.
 		# But in the files collector ($filesref), the original names are saved.
 
-		installer::windows::idtglobal::shorten_feature_gid(\$featurecomponent{'Feature'});
-			
-		$oneline = "$featurecomponent{'Feature'}\t$featurecomponent{'Component'}\n";
-			
-		# control of uniqueness
-			
-		if (! installer::existence::exists_in_array($oneline, $featurecomponenttableref))
+		$feature_name = installer::windows::idtglobal::create_shortend_feature_gid($feature_name);
+
+        my $oneline = sprintf("%s\t%s\n", $feature_name, $component_name);
+		if ( ! installer::existence::exists_in_array($oneline, $featurecomponenttableref))
 		{		
-			push(@{$featurecomponenttableref}, $oneline);
-		}			
-	}				
+			push(@$featurecomponenttableref, $oneline);
+            ++$unique_count;
+		}
+        else
+        {
+            $installer::logger::Lang->printf("feature component pair already exists\n");
+        }
+	}
+    $installer::logger::Lang->printf(
+        "replaced %d (%d) of %d component names in FeatureComponent table\n",
+        $unique_count,
+        $replacement_count,
+        scalar @$registryref);
 }
 
 #################################################################################
 # Collecting all feature that are listed in the featurecomponent table.
 #################################################################################
 
-sub collect_all_feature
+sub collect_all_features
 {
 	my ($featurecomponenttable) = @_;
 	
@@ -145,7 +164,10 @@ sub collect_all_feature
 		{
 			my $feature = $1;
 
-			if (! installer::existence::exists_in_array($feature, \@allfeature)) { push(@allfeature, $feature); }			
+			if (! installer::existence::exists_in_array($feature, \@allfeature))
+            {
+                push(@allfeature, $feature);
+            }
 		}
 	}
 	
@@ -165,7 +187,7 @@ sub check_number_of_components_at_featur
 	$installer::logger::Lang->print("\n");
 	$installer::logger::Lang->print("Checking number of components at features. Maximum is 817 (for Win 98 and Win Me)\n");
 
-	my $allfeature = collect_all_feature($featurecomponenttable);
+	my $allfeature = collect_all_features($featurecomponenttable);
 
 	for ( my $i = 0; $i <= $#{$allfeature}; $i++ )
 	{
@@ -196,7 +218,7 @@ sub check_number_of_components_at_featur
 # Feature Component 
 #################################################################################
 
-sub create_featurecomponent_table
+sub create_featurecomponent_table ($$$)
 {
 	my ($filesref, $registryref, $basedir) = @_;
 	
@@ -216,9 +238,13 @@ sub create_featurecomponent_table
 	# At the moment only the files are related to components (and the files know their modules).
 	# The component for each file is written into the files collector $filesinproductlanguageresolvedarrayref
 			
-	create_featurecomponent_table_from_files_collector(\@featurecomponenttable, $filesref);
-
-	create_featurecomponent_table_from_registry_collector(\@featurecomponenttable, $registryref);
+	create_featurecomponent_table_from_files_collector(
+        \@featurecomponenttable,
+        $filesref);
+
+	create_featurecomponent_table_from_registry_collector(
+        \@featurecomponenttable,
+        $registryref);
 
 	# Additional components have to be added here