1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22
23
24package installer::windows::directory;
25
26use installer::exiter;
27use installer::files;
28use installer::globals;
29use installer::pathanalyzer;
30use installer::windows::idtglobal;
31use installer::windows::msiglobal;
32use installer::scriptitems;
33
34use strict;
35
36##############################################################
37# Collecting all directory trees in global hash
38##############################################################
39
40sub collectdirectorytrees
41{
42	my ( $directoryref ) = @_;
43
44	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
45	{
46		my $onedir = ${$directoryref}[$i];
47		my $styles = "";
48		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
49
50		if ( $styles ne "" )
51		{
52			foreach my $treestyle ( keys %installer::globals::treestyles )
53			{
54				if ( $styles =~ /\b$treestyle\b/ )
55				{
56					my $hostname = $onedir->{'HostName'};
57					# -> hostname is the key, the style the value!
58					$installer::globals::hostnametreestyles{$hostname} = $treestyle;
59				}
60			}
61		}
62	}
63}
64
65##############################################################
66# Overwriting global programfilesfolder, if required
67##############################################################
68
69sub overwrite_programfilesfolder
70{
71	my ( $allvariables ) = @_;
72
73	if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} )
74	{
75		$installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'};
76	}
77}
78
79
80
81
82=head2 make_short_dir_version($longstring)
83
84    Transform the given string into one that is at most 70 characters long.
85    That is done in two steps:
86    - Cut all parts separated by '_' or '-' down to a length of 5.
87    - Cut down the result to a length of 60 and fill it up to length 70
88      with the MD5 checksum.
89
90    This transform always returns the same result for the same string.
91    There is no counter and reference to a global set of names to make the string unique.
92
93=cut
94sub make_short_dir_version ($)
95{
96	my ($longstring) = @_;
97
98	my $shortstring = "";
99	my $cutlength = 60;
100	my $length = 5; # So the directory can still be recognized
101	my $longstring_save = $longstring;
102
103	# Splitting the string at each "underline" and allowing only $length characters per directory name.
104	# Checking also uniqueness and length.
105
106	my @outer_parts = split(/_/, $longstring);
107	foreach my $onestring (@outer_parts)
108	{
109		my $partstring = "";
110
111		if ( $onestring =~ /\-/ )
112		{
113			my @inner_parts = split(/-/, $onestring);
114            @inner_parts = map {substr($_,0,$length)} @inner_parts;
115            $partstring = join("-", @inner_parts);
116			$partstring =~ s/^\s*\-//;
117		}
118		else
119		{
120			$partstring = substr($onestring, 0, $length);
121		}
122
123		$shortstring .= "_" . $partstring;
124	}
125
126	$shortstring =~ s/^\s*\_//;
127
128	# Setting unique ID to each directory
129	# No counter allowed, process must be absolute reproducable due to patch creation process.
130
131	my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits
132	$shortstring = substr($shortstring, 0, $cutlength) . "_" . $subid;
133
134	return $shortstring;
135}
136
137
138
139
140=head2 get_unique_name ($hostname, $unique_map, $shortdirhash, $shortdirhashreverse)
141
142    Return a long and a short unique name for the given $hostname.
143    Despite the function name and unlike the generation of unique
144    names for files, the returned names are not really unique.  Quite
145    the opposite.  The returned names are quaranteed to return the
146    same result for the same input.
147
148    The returned short name has at most length 70.
149
150=cut
151sub get_unique_name ($$)
152{
153    my ($hostname, $hostnamehash) = @_;
154
155    # Make sure that we where not called for this hostname before.  Otherwise the other test would be triggered.
156    if (defined $hostnamehash->{$hostname})
157    {
158        installer::exiter::exit_program(
159            "ERROR: get_unique_name was already called for hostname ".$hostname,
160            "get_unique_name");
161    }
162    $hostnamehash->{$hostname} = 1;
163
164    my $uniquename = $hostname;
165
166    $uniquename =~ s/^\s*//g;				# removing beginning white spaces
167    $uniquename =~ s/\s*$//g;				# removing ending white spaces
168    $uniquename =~ s/\s//g;					# removing white spaces
169    $uniquename =~ s/\_//g;					# removing existing underlines
170    $uniquename =~ s/\.//g;					# removing dots in directoryname
171    $uniquename =~ s/OpenOffice/OO/g;
172
173    $uniquename =~ s/\Q$installer::globals::separator\E/\_/g;	# replacing slash and backslash with underline
174
175    $uniquename =~ s/_registry/_rgy/g;
176    $uniquename =~ s/_registration/_rgn/g;
177    $uniquename =~ s/_extension/_ext/g;
178    $uniquename =~ s/_frame/_frm/g;
179    $uniquename =~ s/_table/_tbl/g;
180    $uniquename =~ s/_chart/_crt/g;
181
182    my $short_uniquename = make_short_dir_version($uniquename);
183
184    return ($uniquename, $short_uniquename);
185}
186
187
188
189
190=head2 check_unique_directorynames($directories)
191
192    The one really important check is made in get_unique_name().  It
193    checks that get_unique_name() is not called twice for the same
194    directory host name.  The tests in this function contain the
195    legacy tests that basically only check if there where a collision
196    of the partial MD5 sum that is used to make the short unique names
197    unique.
198
199    The maps $unique_map, $shortdirhash, $shortdirhashreverse are used
200    only to check that _different_ input names are mapped to different
201    results.  They are not used to influence the result.  That assumes
202    that this function is called only once for every directory
203    hostname.
204=cut
205sub check_unique_directorynames ($)
206{
207    my ($directories) = @_;
208
209    my %completedirhashstep1 = ();
210	my %shortdirhash = ();
211	my %shortdirhashreverse = ();
212
213    # Check unique name of directories.
214    foreach my $directory (@$directories)
215    {
216        my ($long_uniquename, $short_uniquename) = ($directory->{'long_uniquename'}, $directory->{'uniquename'});
217
218        # The names after this small changes must still be unique!
219        if (exists($completedirhashstep1{$long_uniquename}))
220        {
221            installer::exiter::exit_program(
222                sprintf("ERROR: Unallowed modification of directory name, not unique (step 1): \"%s\".",
223                    $short_uniquename),
224                "check_unique_directorynames");
225        }
226        $completedirhashstep1{$long_uniquename} = 1;
227
228
229        # Checking if the same directory already exists, but has another short version.
230        if (exists($shortdirhash{$long_uniquename})
231            && ( $shortdirhash{$long_uniquename} ne $short_uniquename ))
232        {
233            installer::exiter::exit_program(
234                sprintf(
235                    "ERROR: Unallowed modification of directory name, not unique (step 2A): \"%s\".",
236                    $short_uniquename),
237                "check_unique_directorynames");
238        }
239        $shortdirhash{$long_uniquename} = $short_uniquename;
240
241        # Also checking vice versa
242        # Checking if the same short directory already exists, but has another long version.
243        if (exists($shortdirhashreverse{$short_uniquename})
244            && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename ))
245        {
246            installer::exiter::exit_program(
247                sprintf(
248                    "ERROR: Unallowed modification of directory name, not unique (step 2B): \"%s\".",
249                    $short_uniquename),
250                "check_unique_directorynames");
251        }
252        $shortdirhashreverse{$short_uniquename} = $long_uniquename;
253    }
254
255    # Check unique name of parents
256    foreach my $directory (@$directories)
257    {
258        my ($long_uniquename, $short_uniquename)
259            = ($directory->{'long_uniqueparentname'}, $directory->{'uniqueparentname'});
260
261        # Again checking if the same directory already exists, but has another short version.
262        if (exists($shortdirhash{$long_uniquename})
263            && ( $shortdirhash{$long_uniquename} ne $short_uniquename ))
264        {
265            installer::exiter::exit_program(
266                sprintf(
267                    "ERROR: Unallowed modification of directory name, not unique (step 3A): \"%s\".",
268                    $short_uniquename),
269                "check_unique_directorynames");
270        }
271        $shortdirhash{$long_uniquename} = $short_uniquename;
272
273        # Also checking vice versa
274        # Checking if the same short directory already exists, but has another long version.
275        if (exists($shortdirhashreverse{$short_uniquename})
276            && ( $shortdirhashreverse{$short_uniquename} ne $long_uniquename ))
277        {
278            installer::exiter::exit_program(
279                sprintf(
280                    "ERROR: Unallowed modification of directory name, not unique (step 3B): \"%s\".",
281                    $short_uniquename),
282                "check_unique_directorynames");
283        }
284        $shortdirhashreverse{$short_uniquename} = $long_uniquename;
285    }
286}
287
288
289
290
291sub get_unique_parent_name ($$)
292{
293    my ($uniqueparentname, $styles) = @_;
294
295    my $keepparent = 1;
296
297    if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ )	# the underline is now the separator
298    {
299        $uniqueparentname = $1;
300        $keepparent = 0;
301    }
302    else
303    {
304        $uniqueparentname = $installer::globals::programfilesfolder;
305        $keepparent = 1;
306    }
307
308    if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
309    {
310        $uniqueparentname = $installer::globals::programfilesfolder;
311        $keepparent = 1;
312    }
313    if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
314    {
315        $uniqueparentname = $installer::globals::commonfilesfolder;
316        $keepparent = 1;
317    }
318    if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
319    {
320        $uniqueparentname = $installer::globals::commonappdatafolder;
321        $keepparent = 1;
322    }
323    if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
324    {
325        $uniqueparentname = $installer::globals::localappdatafolder;
326        $keepparent = 1;
327    }
328
329    if ( $styles =~ /\bSHAREPOINTPATH\b/ )
330    {
331        $uniqueparentname = "SHAREPOINTPATH";
332        $installer::globals::usesharepointpath = 1;
333        $keepparent = 1;
334    }
335
336    # also setting short directory name for the parent
337
338    my $originaluniqueparentname = $uniqueparentname;
339
340    if ( ! $keepparent )
341    {
342        $uniqueparentname = make_short_dir_version($uniqueparentname);
343    }
344
345    return ($originaluniqueparentname, $uniqueparentname);
346}
347
348
349
350
351##############################################################
352# Adding unique directory names to the directory collection
353##############################################################
354
355sub create_unique_directorynames ($)
356{
357	my ($directories) = @_;
358
359	$installer::globals::officeinstalldirectoryset = 0;
360
361    my %hostnamehash = ();
362	my $infoline = "";
363	my $errorcount = 0;
364
365	foreach my $directory (@$directories)
366	{
367        next if defined $directory->{'uniquename'};
368
369        my $styles = $directory->{'Styles'} // "";
370
371		my ($originaluniquename, $uniquename) = get_unique_name(
372            $directory->{'HostName'},
373            \%hostnamehash);
374
375		my ($originaluniqueparentname, $uniqueparentname) = get_unique_parent_name(
376            $originaluniquename,
377            $styles);
378
379
380		# Hyphen not allowed in database
381		$uniquename =~ s/\-/\_/g;			# making "-" to "_"
382		$uniqueparentname =~ s/\-/\_/g;		# making "-" to "_"
383
384		# And finally setting the values for the directories
385		$directory->{'uniquename'} = $uniquename;
386		$directory->{'uniqueparentname'} = $uniqueparentname;
387		$directory->{'long_uniquename'} = $originaluniquename;
388		$directory->{'long_uniqueparentname'} = $originaluniqueparentname;
389    }
390
391    # Find the installation directory.
392    foreach my $directory (@$directories)
393    {
394        next unless defined $directory->{'Styles'};
395
396		# setting the installlocation directory
397		next unless $directory->{'Styles'} =~ /\bISINSTALLLOCATION\b/;
398
399        if ( $installer::globals::installlocationdirectoryset )
400        {
401            installer::exiter::exit_program(
402                sprintf(
403                    "ERROR: Directory with flag ISINSTALLLOCATION alread set: \"%s\".",
404                    $installer::globals::installlocationdirectory),
405                "create_unique_directorynames");
406        }
407
408        $installer::globals::installlocationdirectory = $directory->{'uniquename'};
409        $installer::globals::installlocationdirectoryset = 1;
410    }
411}
412
413
414
415
416#####################################################
417# Adding ":." to selected default directory names
418#####################################################
419
420sub update_defaultdir ($$)
421{
422	my ( $onedir, $allvariableshashref ) = @_;
423
424	if ($installer::globals::addchildprojects
425        || $installer::globals::patch
426        || $installer::globals::languagepack
427        || $allvariableshashref->{'CHANGETARGETDIR'})
428	{
429		my $sourcediraddon = "\:\.";
430		return $onedir->{'defaultdir'} . $sourcediraddon;
431	}
432	else
433    {
434        return $onedir->{'defaultdir'};
435    }
436}
437
438#####################################################
439# The directory with the style ISINSTALLLOCATION
440# will be replaced by INSTALLLOCATION
441#####################################################
442
443sub set_installlocation_directory
444{
445	my ( $directoryref, $allvariableshashref ) = @_;
446
447	if ( ! $installer::globals::installlocationdirectoryset )
448    {
449        installer::exiter::exit_program(
450            "ERROR: Directory with flag ISINSTALLLOCATION not set!",
451            "set_installlocation_directory");
452    }
453
454	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
455	{
456		my $onedir = ${$directoryref}[$i];
457
458		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
459		{
460			$onedir->{'uniquename'} = "INSTALLLOCATION";
461			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);
462		}
463
464		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
465		{
466			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);
467		}
468
469		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
470		{
471			$onedir->{'uniqueparentname'} = "INSTALLLOCATION";
472		}
473	}
474}
475
476#####################################################
477# Getting the name of the top level directory. This
478# can have only one letter
479#####################################################
480
481sub get_last_directory_name
482{
483	my ($completepathref) = @_;
484
485	if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ )
486	{
487		$$completepathref = $1;
488	}
489}
490
491sub setup_global_font_directory_name ($)
492{
493	my ($directories) = @_;
494
495	foreach my $directory (@$directories)
496	{
497        next unless defined $directory->{'Dir'};
498        next unless defined $directory->{'defaultdir'};
499
500        next if $directory->{'Dir'} ne "PREDEFINED_OSSYSTEMFONTDIR";
501        next if $directory->{'defaultdir'} ne $installer::globals::fontsdirhostname;
502
503        $installer::globals::fontsdirname = $installer::globals::fontsdirhostname;
504        $installer::globals::fontsdirparent = $directory->{'uniqueparentname'};
505
506        $installer::logger::Info->printf("%s, fdhn %s, dd %s, ipn %s, HN %s\n",
507            "PREDEFINED_OSSYSTEMFONTDIR",
508            $installer::globals::fontsdirhostname,
509            $directory->{'defaultdir'},
510            $directory->{'uniqueparentname'},
511            $directory->{'HostName'});
512        installer::scriptitems::print_script_item($directory);
513	}
514}
515
516#####################################################
517# Creating the defaultdir for the file Director.idt
518#####################################################
519
520sub create_defaultdir_directorynames ($)
521{
522	my ($directoryref) = @_;
523
524	my @shortnames = ();
525	if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
526
527	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
528	{
529		my $onedir = ${$directoryref}[$i];
530		my $hostname = $onedir->{'HostName'};
531
532		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;
533		get_last_directory_name(\$hostname);
534		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
535		my $uniquename = $onedir->{'uniquename'};
536		my $shortstring;
537		if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
538		{
539			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
540		}
541		else
542		{
543			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
544		}
545
546		my $defaultdir;
547
548		if ( $shortstring eq $hostname )
549		{
550			$defaultdir = $hostname;
551		}
552		else
553		{
554			$defaultdir = $shortstring . "|" . $hostname;
555		}
556
557		$onedir->{'defaultdir'} = $defaultdir;
558	}
559}
560
561###############################################
562# Fill content into the directory table
563###############################################
564
565sub create_directorytable_from_collection ($$)
566{
567	my ($directorytableref, $directoryref) = @_;
568
569	foreach my $onedir (@$directoryref)
570	{
571        # Remove entries for special directories.
572		if (defined $onedir->{'HostName'}
573            && $onedir->{'HostName'} eq ""
574            && defined $onedir->{'Dir'}
575            && $onedir->{'Dir'} eq "PREDEFINED_PROGDIR")
576        {
577            next;
578        }
579
580		my $oneline = sprintf(
581            "%s\t%s\t%s\n",
582            $onedir->{'uniquename'},
583            $onedir->{'uniqueparentname'},
584            $onedir->{'defaultdir'});
585
586		push @{$directorytableref}, $oneline;
587	}
588}
589
590###############################################
591# Defining the root installation structure
592###############################################
593
594sub process_root_directories ($$)
595{
596	my ($allvariableshashref, $functor) = @_;
597
598	my $oneline = "";
599
600	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
601	{
602		my $productname = $allvariableshashref->{'PRODUCTNAME'};
603		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
604		my $baseproductversion = $productversion;
605
606		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
607		{
608			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
609		}
610
611		my $realproductkey = $productname . " " . $productversion;
612		my $productkey = $productname . " " . $baseproductversion;
613
614		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
615		{
616			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
617			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
618		}
619		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
620		{
621			$productkey =~ s/\ /\_/g;
622			$realproductkey =~ s/\ /\_/g;
623		}
624
625		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir", undef);
626		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
627
628        &$functor(
629            $installer::globals::officemenufolder,
630            $installer::globals::programmenufolder,
631            $shortproductkey . "|". $realproductkey);
632	}
633
634	&$functor("TARGETDIR", "", "SourceDir");
635	&$functor($installer::globals::programfilesfolder, "TARGETDIR", ".");
636    &$functor($installer::globals::programmenufolder, "TARGETDIR", ".");
637    &$functor($installer::globals::startupfolder, "TARGETDIR", ".");
638	&$functor($installer::globals::desktopfolder, "TARGETDIR", ".");
639	&$functor($installer::globals::startmenufolder, "TARGETDIR", ".");
640	&$functor($installer::globals::commonfilesfolder, "TARGETDIR", ".");
641	&$functor($installer::globals::commonappdatafolder, "TARGETDIR", ".");
642	&$functor($installer::globals::localappdatafolder, "TARGETDIR", ".");
643
644	if ( $installer::globals::usesharepointpath )
645	{
646		&$functor("SHAREPOINTPATH", "TARGETDIR", ".");
647	}
648
649	&$functor($installer::globals::systemfolder, "TARGETDIR", ".");
650
651	my $localtemplatefoldername = $installer::globals::templatefoldername;
652	my $directorytableentry = $localtemplatefoldername;
653	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
654	if ( $shorttemplatefoldername ne $localtemplatefoldername )
655    {
656        $directorytableentry = $shorttemplatefoldername . "|" . $localtemplatefoldername;
657    }
658	&$functor($installer::globals::templatefolder, "TARGETDIR", $directorytableentry);
659
660	if ( $installer::globals::fontsdirname )
661	{
662		&$functor(
663             $installer::globals::fontsfolder,
664             $installer::globals::fontsdirparent,
665             $installer::globals::fontsfoldername . ":" . $installer::globals::fontsdirname);
666	}
667	else
668	{
669		&$functor(
670             $installer::globals::fontsfolder,
671             "TARGETDIR",
672             $installer::globals::fontsfoldername);
673	}
674}
675
676
677
678
679sub find_missing_directories ($$)
680{
681    my ($directories, $allvariableshashref) = @_;
682
683    # Set up the list of target directories.
684    my %target_directories = map {$_->{'uniquename'} => 1} @$directories;
685    # Add special directories.
686    process_root_directories(
687        $allvariableshashref,
688        sub($$$){
689            my ($uniquename, $parentname, $defaultdir) = @_;
690            $target_directories{$uniquename} = 1;
691        }
692    );
693
694    # Set up the list of source directories.
695    my $source_directory_map = $installer::globals::source_msi->GetDirectoryMap();
696    my $source_file_map = $installer::globals::source_msi->GetFileMap();
697    my %source_directories = map {$_->{'unique_name'} => $_} values %$source_directory_map;
698
699    # Find the missing source directories.
700    my @missing_directories = ();
701    foreach my $source_uniquename (keys %source_directories)
702    {
703        if ( ! $target_directories{$source_uniquename})
704        {
705            push @missing_directories, $source_directories{$source_uniquename};
706        }
707    }
708
709    # Report the missing directories.
710    $installer::logger::Info->printf("found %d missing directories\n", scalar @missing_directories);
711    my $index = 0;
712    foreach my $directory_item (@missing_directories)
713    {
714        # Print information about the directory.
715        $installer::logger::Info->printf("missing directory %d: %s\n",
716            ++$index,
717            $directory_item->{'full_target_long_name'});
718        while (my($key,$value) = each %$directory_item)
719        {
720            $installer::logger::Info->printf("    %s -> %s\n", $key, $value);
721        }
722
723        # Print the referencing files.
724        my @filenames = ();
725        while (my ($key,$value) = each %$source_file_map)
726        {
727            if ($value->{'directory'}->{'unique_name'} eq $directory_item->{'unique_name'})
728            {
729                push @filenames, $key;
730            }
731        }
732        $installer::logger::Info->printf("  referencing files are %s\n", join(", ", @filenames));
733    }
734
735    foreach my $directory (@$directories)
736    {
737        $installer::logger::Lang->printf("target directory %s -> HN %s\n",
738            $directory->{'uniquename'},
739            $directory->{'HostName'});
740        installer::scriptitems::print_script_item($directory);
741    }
742
743    # Setup a map of directory uniquenames to verify that the new
744    # entries don't use unique names that are already in use.
745    my %unique_names = map {$_->{'uniquename'} => $_} @$directories;
746
747    # Create script items for the missing directories.
748    my @new_source_directories = ();
749    foreach my $source_directory_item (@missing_directories)
750    {
751        my $new_directory_item = {
752            'uniquename' => $source_directory_item->{'unique_name'},
753            'uniqueparentname' => $source_directory_item->{'parent_name'},
754            'defaultdir' => $source_directory_item->{'default_dir'},
755            'HostName' => $source_directory_item->{'full_target_long_name'},
756            'componentname' => $source_directory_item->{'component_name'},
757        };
758
759        if (defined $unique_names{$new_directory_item->{'uniquename'}})
760        {
761            installer::logger::PrintError("newly created directory entry collides with existing directory");
762            last;
763        }
764
765        push @new_source_directories, $new_directory_item;
766    }
767
768    return @new_source_directories;
769}
770
771
772
773
774sub prepare_directory_table_creation ($$)
775{
776	my ($directories, $allvariableshashref) = @_;
777
778    foreach my $directory (@$directories)
779    {
780        delete $directory->{'uniquename'};
781    }
782
783	overwrite_programfilesfolder($allvariableshashref);
784	create_unique_directorynames($directories);
785    check_unique_directorynames($directories);
786	create_defaultdir_directorynames($directories);	# only destdir!
787    setup_global_font_directory_name($directories);
788	set_installlocation_directory($directories, $allvariableshashref);
789
790    if ($installer::globals::is_release)
791    {
792        my @new_directories = find_missing_directories($directories, $allvariableshashref);
793        push @$directories, @new_directories;
794    }
795}
796
797
798
799
800###############################################
801# Creating the file Director.idt dynamically
802###############################################
803
804sub create_directory_table ($$$)
805{
806	my ($directoryref, $basedir, $allvariableshashref) = @_;
807
808	# Structure of the directory table:
809	# Directory Directory_Parent DefaultDir
810	# Directory is a unique identifier
811	# Directory_Parent is the unique identifier of the parent
812	# DefaultDir is .:APPLIC~1|Application Data with
813	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
814	# After ":" : 8+3 and not 8+3 the destination directory name
815
816	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");
817
818	my @directorytable = ();
819	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
820
821    # Add entries for the root directories (and a few special directories like that for fonts).
822    process_root_directories(
823        $allvariableshashref,
824        sub($$$){
825            push(@directorytable, join("\t", @_)."\n");
826        }
827    );
828
829    # Add entries for the non-root directories.
830	create_directorytable_from_collection(\@directorytable, $directoryref);
831
832	# Saving the file
833
834	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
835	installer::files::save_file($directorytablename ,\@directorytable);
836    $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename);
837
838	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
839}
840
841
8421;
843