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 reproducible 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        $styles = "" unless defined $styles;
371
372		my ($originaluniquename, $uniquename) = get_unique_name(
373            $directory->{'HostName'},
374            \%hostnamehash);
375
376		my ($originaluniqueparentname, $uniqueparentname) = get_unique_parent_name(
377            $originaluniquename,
378            $styles);
379
380
381		# Hyphen not allowed in database
382		$uniquename =~ s/\-/\_/g;			# making "-" to "_"
383		$uniqueparentname =~ s/\-/\_/g;		# making "-" to "_"
384
385		# And finally setting the values for the directories
386		$directory->{'uniquename'} = $uniquename;
387		$directory->{'uniqueparentname'} = $uniqueparentname;
388		$directory->{'long_uniquename'} = $originaluniquename;
389		$directory->{'long_uniqueparentname'} = $originaluniqueparentname;
390    }
391
392    # Find the installation directory.
393    foreach my $directory (@$directories)
394    {
395        next unless defined $directory->{'Styles'};
396
397		# setting the installlocation directory
398		next unless $directory->{'Styles'} =~ /\bISINSTALLLOCATION\b/;
399
400        if ( $installer::globals::installlocationdirectoryset )
401        {
402            installer::exiter::exit_program(
403                sprintf(
404                    "ERROR: Directory with flag ISINSTALLLOCATION alread set: \"%s\".",
405                    $installer::globals::installlocationdirectory),
406                "create_unique_directorynames");
407        }
408
409        $installer::globals::installlocationdirectory = $directory->{'uniquename'};
410        $installer::globals::installlocationdirectoryset = 1;
411    }
412}
413
414
415
416
417#####################################################
418# Adding ":." to selected default directory names
419#####################################################
420
421sub update_defaultdir ($$)
422{
423	my ( $onedir, $allvariableshashref ) = @_;
424
425	if ($installer::globals::addchildprojects
426        || $installer::globals::patch
427        || $installer::globals::languagepack
428        || $allvariableshashref->{'CHANGETARGETDIR'})
429	{
430		my $sourcediraddon = "\:\.";
431		return $onedir->{'defaultdir'} . $sourcediraddon;
432	}
433	else
434    {
435        return $onedir->{'defaultdir'};
436    }
437}
438
439#####################################################
440# The directory with the style ISINSTALLLOCATION
441# will be replaced by INSTALLLOCATION
442#####################################################
443
444sub set_installlocation_directory
445{
446	my ( $directoryref, $allvariableshashref ) = @_;
447
448	if ( ! $installer::globals::installlocationdirectoryset )
449    {
450        installer::exiter::exit_program(
451            "ERROR: Directory with flag ISINSTALLLOCATION not set!",
452            "set_installlocation_directory");
453    }
454
455	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
456	{
457		my $onedir = ${$directoryref}[$i];
458
459		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
460		{
461			$onedir->{'uniquename'} = "INSTALLLOCATION";
462			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);
463		}
464
465		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
466		{
467			$onedir->{'defaultdir'} = update_defaultdir($onedir, $allvariableshashref);
468		}
469
470		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
471		{
472			$onedir->{'uniqueparentname'} = "INSTALLLOCATION";
473		}
474	}
475}
476
477#####################################################
478# Getting the name of the top level directory. This
479# can have only one letter
480#####################################################
481
482sub get_last_directory_name
483{
484	my ($completepathref) = @_;
485
486	if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ )
487	{
488		$$completepathref = $1;
489	}
490}
491
492sub setup_global_font_directory_name ($)
493{
494	my ($directories) = @_;
495
496	foreach my $directory (@$directories)
497	{
498        next unless defined $directory->{'Dir'};
499        next unless defined $directory->{'defaultdir'};
500
501        next if $directory->{'Dir'} ne "PREDEFINED_OSSYSTEMFONTDIR";
502        next if $directory->{'defaultdir'} ne $installer::globals::fontsdirhostname;
503
504        $installer::globals::fontsdirname = $installer::globals::fontsdirhostname;
505        $installer::globals::fontsdirparent = $directory->{'uniqueparentname'};
506
507        $installer::logger::Info->printf("%s, fdhn %s, dd %s, ipn %s, HN %s\n",
508            "PREDEFINED_OSSYSTEMFONTDIR",
509            $installer::globals::fontsdirhostname,
510            $directory->{'defaultdir'},
511            $directory->{'uniqueparentname'},
512            $directory->{'HostName'});
513        installer::scriptitems::print_script_item($directory);
514	}
515}
516
517#####################################################
518# Creating the defaultdir for the file Director.idt
519#####################################################
520
521sub create_defaultdir_directorynames ($)
522{
523	my ($directoryref) = @_;
524
525	my @shortnames = ();
526	if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
527
528	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
529	{
530		my $onedir = ${$directoryref}[$i];
531		my $hostname = $onedir->{'HostName'};
532
533		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;
534		get_last_directory_name(\$hostname);
535		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
536		my $uniquename = $onedir->{'uniquename'};
537		my $shortstring;
538		if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
539		{
540			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
541		}
542		else
543		{
544			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
545		}
546
547		my $defaultdir;
548
549		if ( $shortstring eq $hostname )
550		{
551			$defaultdir = $hostname;
552		}
553		else
554		{
555			$defaultdir = $shortstring . "|" . $hostname;
556		}
557
558		$onedir->{'defaultdir'} = $defaultdir;
559	}
560}
561
562###############################################
563# Fill content into the directory table
564###############################################
565
566sub create_directorytable_from_collection ($$)
567{
568	my ($directorytableref, $directoryref) = @_;
569
570	foreach my $onedir (@$directoryref)
571	{
572        # Remove entries for special directories.
573		if (defined $onedir->{'HostName'}
574            && $onedir->{'HostName'} eq ""
575            && defined $onedir->{'Dir'}
576            && $onedir->{'Dir'} eq "PREDEFINED_PROGDIR")
577        {
578            next;
579        }
580
581		my $oneline = sprintf(
582            "%s\t%s\t%s\n",
583            $onedir->{'uniquename'},
584            $onedir->{'uniqueparentname'},
585            $onedir->{'defaultdir'});
586
587		push @{$directorytableref}, $oneline;
588	}
589}
590
591###############################################
592# Defining the root installation structure
593###############################################
594
595sub process_root_directories ($$)
596{
597	my ($allvariableshashref, $functor) = @_;
598
599	my $oneline = "";
600
601	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
602	{
603		my $productname = $allvariableshashref->{'PRODUCTNAME'};
604		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
605		my $baseproductversion = $productversion;
606
607		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
608		{
609			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
610		}
611
612		my $realproductkey = $productname . " " . $productversion;
613		my $productkey = $productname . " " . $baseproductversion;
614
615		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
616		{
617			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
618			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
619		}
620		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
621		{
622			$productkey =~ s/\ /\_/g;
623			$realproductkey =~ s/\ /\_/g;
624		}
625
626		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir", undef);
627		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
628
629        &$functor(
630            $installer::globals::officemenufolder,
631            $installer::globals::programmenufolder,
632            $shortproductkey . "|". $realproductkey);
633	}
634
635	&$functor("TARGETDIR", "", "SourceDir");
636	&$functor($installer::globals::programfilesfolder, "TARGETDIR", ".");
637    &$functor($installer::globals::programmenufolder, "TARGETDIR", ".");
638    &$functor($installer::globals::startupfolder, "TARGETDIR", ".");
639	&$functor($installer::globals::desktopfolder, "TARGETDIR", ".");
640	&$functor($installer::globals::startmenufolder, "TARGETDIR", ".");
641	&$functor($installer::globals::commonfilesfolder, "TARGETDIR", ".");
642	&$functor($installer::globals::commonappdatafolder, "TARGETDIR", ".");
643	&$functor($installer::globals::localappdatafolder, "TARGETDIR", ".");
644
645	if ( $installer::globals::usesharepointpath )
646	{
647		&$functor("SHAREPOINTPATH", "TARGETDIR", ".");
648	}
649
650	&$functor($installer::globals::systemfolder, "TARGETDIR", ".");
651
652	my $localtemplatefoldername = $installer::globals::templatefoldername;
653	my $directorytableentry = $localtemplatefoldername;
654	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
655	if ( $shorttemplatefoldername ne $localtemplatefoldername )
656    {
657        $directorytableentry = $shorttemplatefoldername . "|" . $localtemplatefoldername;
658    }
659	&$functor($installer::globals::templatefolder, "TARGETDIR", $directorytableentry);
660
661	if ( $installer::globals::fontsdirname )
662	{
663		&$functor(
664             $installer::globals::fontsfolder,
665             $installer::globals::fontsdirparent,
666             $installer::globals::fontsfoldername . ":" . $installer::globals::fontsdirname);
667	}
668	else
669	{
670		&$functor(
671             $installer::globals::fontsfolder,
672             "TARGETDIR",
673             $installer::globals::fontsfoldername);
674	}
675}
676
677
678
679
680sub find_missing_directories ($$)
681{
682    my ($directories, $allvariableshashref) = @_;
683
684    # Set up the list of target directories.
685    my %target_directories = map {$_->{'uniquename'} => 1} @$directories;
686    # Add special directories.
687    process_root_directories(
688        $allvariableshashref,
689        sub($$$){
690            my ($uniquename, $parentname, $defaultdir) = @_;
691            $target_directories{$uniquename} = 1;
692        }
693    );
694
695    # Set up the list of source directories.
696    my $source_directory_map = $installer::globals::source_msi->GetDirectoryMap();
697    my $source_file_map = $installer::globals::source_msi->GetFileMap();
698    my %source_directories = map {$_->{'unique_name'} => $_} values %$source_directory_map;
699
700    # Find the missing source directories.
701    my @missing_directories = ();
702    foreach my $source_uniquename (keys %source_directories)
703    {
704        if ( ! $target_directories{$source_uniquename})
705        {
706            push @missing_directories, $source_directories{$source_uniquename};
707        }
708    }
709
710    # Report the missing directories.
711    $installer::logger::Info->printf("found %d missing directories\n", scalar @missing_directories);
712    my $index = 0;
713    foreach my $directory_item (@missing_directories)
714    {
715        # Print information about the directory.
716        $installer::logger::Info->printf("missing directory %d: %s\n",
717            ++$index,
718            $directory_item->{'full_target_long_name'});
719        while (my($key,$value) = each %$directory_item)
720        {
721            $installer::logger::Info->printf("    %s -> %s\n", $key, $value);
722        }
723
724        # Print the referencing files.
725        my @filenames = ();
726        while (my ($key,$value) = each %$source_file_map)
727        {
728            if ($value->{'directory'}->{'unique_name'} eq $directory_item->{'unique_name'})
729            {
730                push @filenames, $key;
731            }
732        }
733        $installer::logger::Info->printf("  referencing files are %s\n", join(", ", @filenames));
734    }
735
736    foreach my $directory (@$directories)
737    {
738        $installer::logger::Lang->printf("target directory %s -> HN %s\n",
739            $directory->{'uniquename'},
740            $directory->{'HostName'});
741        installer::scriptitems::print_script_item($directory);
742    }
743
744    # Setup a map of directory uniquenames to verify that the new
745    # entries don't use unique names that are already in use.
746    my %unique_names = map {$_->{'uniquename'} => $_} @$directories;
747
748    # Create script items for the missing directories.
749    my @new_source_directories = ();
750    foreach my $source_directory_item (@missing_directories)
751    {
752        my $new_directory_item = {
753            'uniquename' => $source_directory_item->{'unique_name'},
754            'uniqueparentname' => $source_directory_item->{'parent_name'},
755            'defaultdir' => $source_directory_item->{'default_dir'},
756            'HostName' => $source_directory_item->{'full_target_long_name'},
757            'componentname' => $source_directory_item->{'component_name'},
758        };
759
760        if (defined $unique_names{$new_directory_item->{'uniquename'}})
761        {
762            installer::logger::PrintError("newly created directory entry collides with existing directory");
763            last;
764        }
765
766        push @new_source_directories, $new_directory_item;
767    }
768
769    return @new_source_directories;
770}
771
772
773
774
775sub prepare_directory_table_creation ($$)
776{
777	my ($directories, $allvariableshashref) = @_;
778
779    foreach my $directory (@$directories)
780    {
781        delete $directory->{'uniquename'};
782    }
783
784	overwrite_programfilesfolder($allvariableshashref);
785	create_unique_directorynames($directories);
786    check_unique_directorynames($directories);
787	create_defaultdir_directorynames($directories);	# only destdir!
788    setup_global_font_directory_name($directories);
789	set_installlocation_directory($directories, $allvariableshashref);
790
791    if ($installer::globals::is_release)
792    {
793        my @new_directories = find_missing_directories($directories, $allvariableshashref);
794        push @$directories, @new_directories;
795    }
796}
797
798
799
800
801###############################################
802# Creating the file Director.idt dynamically
803###############################################
804
805sub create_directory_table ($$$)
806{
807	my ($directoryref, $basedir, $allvariableshashref) = @_;
808
809	# Structure of the directory table:
810	# Directory Directory_Parent DefaultDir
811	# Directory is a unique identifier
812	# Directory_Parent is the unique identifier of the parent
813	# DefaultDir is .:APPLIC~1|Application Data with
814	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
815	# After ":" : 8+3 and not 8+3 the destination directory name
816
817	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");
818
819	my @directorytable = ();
820	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
821
822    # Add entries for the root directories (and a few special directories like that for fonts).
823    process_root_directories(
824        $allvariableshashref,
825        sub($$$){
826            push(@directorytable, join("\t", @_)."\n");
827        }
828    );
829
830    # Add entries for the non-root directories.
831	create_directorytable_from_collection(\@directorytable, $directoryref);
832
833	# Saving the file
834
835	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
836	installer::files::save_file($directorytablename ,\@directorytable);
837    $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename);
838
839	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
840}
841
842
8431;
844