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

svn commit: r1551937 [18/29] - in /openoffice/branches/ooxml-osba: ./ extras/l10n/source/bg/ extras/l10n/source/de/ extras/l10n/source/nb/ extras/l10n/source/th/ main/ main/accessibility/inc/accessibility/extended/ main/accessibility/inc/accessibility/...

Modified: openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/directory.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/directory.pm?rev=1551937&r1=1551936&r2=1551937&view=diff
==============================================================================
--- openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/directory.pm (original)
+++ openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/directory.pm Wed Dec 18 13:27:09 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,185 +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;
-			if ( $installer::globals::installlocationdirectory =~ /oracle_/i ) { $installer::globals::sundirexists = 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'};
+    }
 }
 
 #####################################################
@@ -310,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++ )
 	{
@@ -319,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 )
@@ -349,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); }
@@ -391,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'};
-		}
 	}
 }
 
@@ -410,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;
 	}
 }
 
@@ -434,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'} ))
@@ -474,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_name'},
+            '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
@@ -556,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
@@ -579,4 +838,5 @@ sub create_directory_table
 	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
 }
 
+
 1;

Modified: openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/feature.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/feature.pm?rev=1551937&r1=1551936&r2=1551937&view=diff
==============================================================================
--- openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/feature.pm (original)
+++ openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/feature.pm Wed Dec 18 13:27:09 2013
@@ -363,78 +363,140 @@ sub add_uniquekey
 # Feature Feature_Parent Title Description Display Level Directory_ Attributes
 #################################################################################
 
-sub create_feature_table
+sub prepare_feature_table ($$$)
 {
-	my ($modulesref, $basedir, $languagesarrayref, $allvariableshashref) = @_;
+	my ($modules, $language, $variables) = @_;
 
-	for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ )
-	{
-		my $onelanguage = ${$languagesarrayref}[$m];
-	
-		my $infoline;
-
-		my @featuretable = ();
-
-		installer::windows::idtglobal::write_idt_header(\@featuretable, "feature");
-
-		for ( my $i = 0; $i <= $#{$modulesref}; $i++ )
-		{
-			my $onefeature = ${$modulesref}[$i];
-
-			# Java and Ada only, if the correct settings are set
-			my $styles = "";
-			if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; }
-			if (( $styles =~ /\bJAVAMODULE\b/ ) && ( ! ($allvariableshashref->{'JAVAPRODUCT'} ))) { next; }
-			if (( $styles =~ /\bADAMODULE\b/ ) && ( ! ($allvariableshashref->{'ADAPRODUCT'} ))) { next; }
-
-			# Controlling the language!
-			# Only language independent feature or feature with the correct language will be included into the table
-			
-			if (! (!(( $onefeature->{'ismultilingual'} )) || ( $onefeature->{'specificlanguage'} eq $onelanguage )) )  { next; }
-
-			my %feature = ();
-		
-			$feature{'feature'} = get_feature_gid($onefeature);
-			$feature{'feature_parent'} = get_feature_parent($onefeature);
-			# if ( $onefeature->{'ParentID'} eq "" ) { $feature{'feature_parent'} = ""; }	# Root has no parent
-			$feature{'Title'} = $onefeature->{'Name'};
-			$feature{'Description'} = $onefeature->{'Description'};
-			$feature{'Display'} = get_feature_display($onefeature);
-			$feature{'Level'} = get_feature_level($onefeature);
-			$feature{'Directory_'} = get_feature_directory($onefeature);
-			$feature{'Attributes'} = get_feature_attributes($onefeature);
-
-			my $oneline = $feature{'feature'} . "\t" . $feature{'feature_parent'} . "\t" . $feature{'Title'} . "\t"  
-					. $feature{'Description'} . "\t" . $feature{'Display'} . "\t" . $feature{'Level'} . "\t"
-					. $feature{'Directory_'} . "\t" . $feature{'Attributes'} . "\n";
-
-			push(@featuretable, $oneline);
-
-			# collecting all feature in global feature collector (so that properties can be set in property table)
-			if ( ! installer::existence::exists_in_array($feature{'feature'}, \@installer::globals::featurecollector) )
-			{
-				push(@installer::globals::featurecollector, $feature{'feature'});
-			}
-			
-			# collecting all language feature in feature collector for check of language selection
-			if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( $onefeature->{'ParentID'} ne $installer::globals::rootmodulegid ))
-			{
-				$installer::globals::multilingual_only_modules{$feature{'feature'}} = 1;
-			}
-
-			# collecting all application feature in global feature collector for check of application selection
-			if ( $styles =~ /\bAPPLICATIONMODULE\b/ )
-			{
-				$installer::globals::application_modules{$feature{'feature'}} = 1;
-			}
-		}
-
-		# Saving the file
-		
-		my $featuretablename = $basedir . $installer::globals::separator . "Feature.idt" . "." . $onelanguage;
-		installer::files::save_file($featuretablename ,\@featuretable);
-        $installer::logger::Lang->printf("Created idt file: %s\n", $featuretablename); 
-	}
+    my $features = [];
+    
+    foreach my $onefeature (@$modules)
+    {
+        # Java and Ada only, if the correct settings are set
+        my $styles = $onefeature->{'Styles'} // "";
+        if (( $styles =~ /\bJAVAMODULE\b/ ) && ( ! ($variables->{'JAVAPRODUCT'} ))) { next; }
+
+        # Controlling the language!
+        # Only language independent feature or feature with the correct language will be included into the table
+        
+        next if $onefeature->{'ismultilingual'} && ($onefeature->{'specificlanguage'} ne $language);
+
+        my $feature_gid =get_feature_gid($onefeature);
+
+        my $feature = {
+            'Feature' => $feature_gid,
+            'Feature_Parent' => get_feature_parent($onefeature),
+            'Title' => $onefeature->{'Name'},
+            'Description' => $onefeature->{'Description'},
+            'Display' => get_feature_display($onefeature),
+            'Level' => get_feature_level($onefeature),
+            'Directory_' => get_feature_directory($onefeature),
+            'Attributes' => get_feature_attributes($onefeature)
+        };
+        push @$features, $feature;
+
+        # collecting all feature in global feature collector (so that properties can be set in property table)
+        $installer::globals::featurecollector{$feature_gid} = 1;
+        
+        # collecting all language feature in feature collector for check of language selection
+        if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && $onefeature->{'ParentID'} ne $installer::globals::rootmodulegid)
+        {
+            $installer::globals::multilingual_only_modules{$feature_gid} = 1;
+        }
+
+        # collecting all application feature in global feature collector for check of application selection
+        if ( $styles =~ /\bAPPLICATIONMODULE\b/ )
+        {
+            $installer::globals::application_modules{$feature_gid} = 1;
+        }
+    }
+
+    return $features;
+}
+
+
+
+
+=head add_missing_features($features)
+
+    When we are building a release, then there may be features missing
+    that where present in the source release.  As missing features
+    would prevent patches from being created, we add the missing
+    features.
+
+    The returned feature hash is either identical to the given
+    $features or is a copy with the missing features added.
+
+=cut
+
+sub add_missing_features ($)
+{
+    my ($features) = @_;
+
+    return $features if ! $installer::globals::is_release;
+
+    # Aquire the feature list of the source release.
+    my $source_feature_table = $installer::globals::source_msi->GetTable("Feature");
+    my $feature_column_index = $source_feature_table->GetColumnIndex("Feature");
+
+    # Prepare fast lookup of the target features.
+    my %target_feature_map = map {$_->{'Feature'} => $_} @$features;
+    
+    # Find missing features.
+    my @missing_features = ();
+    foreach my $source_feature_row (@{$source_feature_table->GetAllRows()})
+    {
+        my $feature_gid = $source_feature_row->GetValue($feature_column_index);
+        if ( ! defined $target_feature_map{$feature_gid})
+        {
+            push @missing_features, $source_feature_row;
+        }
+    }
+
+    # Return when there are no missing features.
+    return $features if scalar @missing_features==0;
+    
+    # Process the missing features.
+    my $extended_features = [@$features];
+    foreach my $missing_feature_row (@missing_features)
+    {
+        my %feature = map
+            {$_ => $missing_feature_row->GetValue($_)}
+            ('Feature', 'Feature_Parent', 'Title', 'Description', 'Display', 'Level', 'Directory_', 'Attributes');
+        push @$extended_features, \%feature;
+        
+        $installer::logger::Lang->printf("added missing feature %s\n", $feature->{'Feature'}); 
+    }
+    return $extended_features;
+}
+
+
+
+
+sub create_feature_table ($$$)
+{
+	my ($basedir, $language, $features) = @_;
+
+    my @feature_table = ();
+    installer::windows::idtglobal::write_idt_header(\@feature_table, "feature");
+
+    foreach my $feature (@$features)
+    {
+        my $line = join("\t",
+            $feature->{'Feature'},
+            $feature->{'Feature_Parent'},
+            $feature->{'Title'},
+            $feature->{'Description'},
+            $feature->{'Display'},
+            $feature->{'Level'},
+            $feature->{'Directory_'},
+            $feature->{'Attributes'}) . "\n";
+
+        push(@feature_table, $line);
+    }
+
+    my $filename = $basedir . $installer::globals::separator . "Feature.idt" . "." . $language;
+    installer::files::save_file($filename ,\@feature_table);
+    $installer::logger::Lang->printf("Created idt file: %s\n", $filename); 
 }
 
 1;

Modified: openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/featurecomponent.pm
URL: http://svn.apache.org/viewvc/openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/featurecomponent.pm?rev=1551937&r1=1551936&r2=1551937&view=diff
==============================================================================
--- openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/featurecomponent.pm (original)
+++ openoffice/branches/ooxml-osba/main/solenv/bin/modules/installer/windows/featurecomponent.pm Wed Dec 18 13:27:09 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