2 # This file is part of the LibreOffice project.
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 # This file incorporates work covered by the following license notice:
10 # Licensed to the Apache Software Foundation (ASF) under one or more
11 # contributor license agreements. See the NOTICE file distributed
12 # with this work for additional information regarding copyright
13 # ownership. The ASF licenses this file to you under the Apache
14 # License, Version 2.0 (the "License"); you may not use this file
15 # except in compliance with the License. You may obtain a copy of
16 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package installer
::windows
::directory
;
21 use installer
::exiter
;
23 use installer
::globals
;
24 use installer
::pathanalyzer
;
25 use installer
::windows
::idtglobal
;
26 use installer
::windows
::msiglobal
;
28 ##############################################################
29 # Collecting all directory trees in global hash
30 ##############################################################
32 sub collectdirectorytrees
34 my ( $directoryref ) = @_;
36 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
38 my $onedir = ${$directoryref}[$i];
40 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
44 foreach my $treestyle ( keys %installer::globals
::treestyles
)
46 if ( $styles =~ /\b$treestyle\b/ )
48 my $hostname = $onedir->{'HostName'};
49 # -> hostname is the key, the style the value!
50 $installer::globals
::hostnametreestyles
{$hostname} = $treestyle;
57 ##############################################################
58 # Overwriting global programfilesfolder, if required
59 ##############################################################
61 sub overwrite_programfilesfolder
63 my ( $allvariables ) = @_;
65 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 ))
67 $installer::globals
::programfilesfolder
= "ProgramFiles64Folder";
71 ##############################################################
72 # Maximum length of directory name is 72.
73 # Taking care of underlines, which are the separator.
74 ##############################################################
76 sub make_short_dir_version
78 my ($longstring) = @_;
82 my $length = 5; # So the directory can still be recognized
83 my $longstring_save = $longstring;
85 # Splitting the string at each "underline" and allowing only
86 # $length characters per directory name.
87 # Checking also uniqueness and length.
89 for my $onestring ( split /_\s*/, $longstring )
93 if ( $onestring =~ /\-/ )
95 for my $onelocalstring ( split /-\s*/, $onestring )
97 if ( length($onelocalstring) > $length ) {
98 $onelocalstring = substr($onelocalstring, 0, $length);
100 $partstring .= "-" . $onelocalstring;
102 $partstring =~ s/^\s*\-//;
106 if ( length($onestring) > $length ) {
107 $partstring = substr($onestring, 0, $length);
110 $partstring = $onestring;
114 $shortstring .= "_" . $partstring;
117 $shortstring =~ s/^\s*\_//;
119 # Setting unique ID to each directory
120 # No counter allowed, process must be absolute reproducible due to patch creation process.
122 # chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`); # Very, very slow
123 # my $subid = substr($id, 0, 9); # taking only the first 9 digits
125 my $subid = installer
::windows
::msiglobal
::calculate_id
($longstring_save, 9); # taking only the first 9 digits
127 if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }
129 $shortstring = $shortstring . "_" . $subid;
134 ##############################################################
135 # Adding unique directory names to the directory collection
136 ##############################################################
138 my $already_checked_the_frigging_directories_for_uniqueness = 0;
140 sub create_unique_directorynames
142 my ($directoryref, $allvariables) = @_;
144 my %completedirhashstep1 = ();
145 my %shortdirhash = ();
146 my %shortdirhashreverse = ();
149 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
151 my $onedir = ${$directoryref}[$i];
152 my $uniquename = $onedir->{'HostName'};
155 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
157 $uniquename =~ s/^\s*//g; # removing beginning white spaces
158 $uniquename =~ s/\s*$//g; # removing ending white spaces
159 $uniquename =~ s/\s//g; # removing white spaces
160 $uniquename =~ s/\_//g; # removing existing underlines
161 $uniquename =~ s/\.//g; # removing dots in directoryname
162 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline
163 $uniquename =~ s/OpenOffice/OO/g;
164 $uniquename =~ s/LibreOffice/LO/g;
165 $uniquename =~ s/_registry/_rgy/g;
166 $uniquename =~ s/_registration/_rgn/g;
167 $uniquename =~ s/_extension/_ext/g;
168 $uniquename =~ s/_frame/_frm/g;
169 $uniquename =~ s/_table/_tbl/g;
170 $uniquename =~ s/_chart/_crt/g;
171 $uniquename =~ s/_plat-linux/_plx/g;
173 # The names after this small changes must still be unique!
174 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"); }
175 $completedirhashstep1{$uniquename} = 1;
177 # Starting to make unique name for the parent and its directory
178 my $originaluniquename = $uniquename;
180 $uniquename = make_short_dir_version
($uniquename);
182 # Checking if the same directory already exists, but has another short version.
183 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"); }
185 # Also checking vice versa
186 # Checking if the same short directory already exists, but has another long version.
187 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"); }
189 # Creating assignment from long to short directory names
190 $shortdirhash{$originaluniquename} = $uniquename;
191 $shortdirhashreverse{$uniquename} = $originaluniquename;
193 # Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).
195 my $uniqueparentname = $originaluniquename;
198 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator
200 $uniqueparentname = $1;
205 $uniqueparentname = $installer::globals
::programfilesfolder
;
209 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
211 $uniqueparentname = $installer::globals
::programfilesfolder
;
214 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
216 $uniqueparentname = $installer::globals
::commonfilesfolder
;
219 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
221 $uniqueparentname = $installer::globals
::commonappdatafolder
;
224 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
226 $uniqueparentname = $installer::globals
::localappdatafolder
;
230 if ( $styles =~ /\bSHAREPOINTPATH\b/ )
232 $uniqueparentname = "SHAREPOINTPATH";
233 $installer::globals
::usesharepointpath
= 1;
237 # also setting short directory name for the parent
239 my $originaluniqueparentname = $uniqueparentname;
243 $uniqueparentname = make_short_dir_version
($uniqueparentname);
246 # Again checking if the same directory already exists, but has another short version.
247 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"); }
249 # Also checking vice versa
250 # Checking if the same short directory already exists, but has another long version.
251 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"); }
253 $shortdirhash{$originaluniqueparentname} = $uniqueparentname;
254 $shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
256 # Hyphen not allowed in database
257 $uniquename =~ s/\-/\_/g; # making "-" to "_"
258 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_"
260 # And finally setting the values for the directories
261 $onedir->{'uniquename'} = $uniquename;
262 $onedir->{'uniqueparentname'} = $uniqueparentname;
264 # setting the installlocation directory
265 if ( $styles =~ /\bISINSTALLLOCATION\b/ )
267 if ( $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
268 $installer::globals
::installlocationdirectory
= $uniquename;
269 $installer::globals
::installlocationdirectoryset
= 1;
274 #####################################################
275 # Adding ":." to selected default directory names
276 #####################################################
278 sub check_sourcedir_addon
280 my ( $onedir, $allvariableshashref ) = @_;
282 if (($installer::globals
::languagepack
) ||
283 ($installer::globals
::helppack
) ||
284 ($allvariableshashref->{'CHANGETARGETDIR'}))
286 my $sourcediraddon = "\:\.";
287 $onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
292 #####################################################
293 # The directory with the style ISINSTALLLOCATION
294 # will be replaced by INSTALLLOCATION
295 #####################################################
297 sub set_installlocation_directory
299 my ( $directoryref, $allvariableshashref ) = @_;
301 if ( ! $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
303 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
305 my $onedir = ${$directoryref}[$i];
307 if ( $onedir->{'uniquename'} eq $installer::globals
::installlocationdirectory
)
309 $onedir->{'uniquename'} = "INSTALLLOCATION";
310 check_sourcedir_addon
($onedir, $allvariableshashref);
313 if ( $onedir->{'uniquename'} eq $installer::globals
::vendordirectory
)
315 check_sourcedir_addon
($onedir, $allvariableshashref);
318 if ( $onedir->{'uniqueparentname'} eq $installer::globals
::installlocationdirectory
)
320 $onedir->{'uniqueparentname'} = "INSTALLLOCATION";
325 #####################################################
326 # Getting the name of the top level directory. This
327 # can have only one letter
328 #####################################################
330 sub get_last_directory_name
332 my ($completepathref) = @_;
334 if ( $$completepathref =~ /^.*[\/\\](.+?
)\s
*$/ )
336 $$completepathref = $1;
340 #####################################################
341 # Creating the defaultdir for the file Director.idt
342 #####################################################
344 sub create_defaultdir_directorynames
346 my ($directoryref, $shortdirnamehashref) = @_;
349 if ( $installer::globals
::updatedatabase
) { @shortnames = values(%{$shortdirnamehashref}); }
350 elsif ( $installer::globals
::prepare_winpatch
) { @shortnames = values(%installer::globals
::saved83dirmapping
); }
352 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
354 my $onedir = ${$directoryref}[$i];
355 my $hostname = $onedir->{'HostName'};
357 $hostname =~ s/\Q$installer::globals::separator\E\s*$//;
358 get_last_directory_name
(\
$hostname);
359 my $uniquename = $onedir->{'uniquename'};
361 if (( $installer::globals
::updatedatabase
) && ( exists($shortdirnamehashref->{$uniquename}) ))
363 $shortstring = $shortdirnamehashref->{$uniquename};
365 elsif (( $installer::globals
::prepare_winpatch
) && ( exists($installer::globals
::saved83dirmapping
{$uniquename}) ))
367 $shortstring = $installer::globals
::saved83dirmapping
{$uniquename};
371 $shortstring = installer
::windows
::idtglobal
::make_eight_three_conform
($hostname, "dir", \
@shortnames);
376 if ( $shortstring eq $hostname )
378 $defaultdir = $hostname;
382 $defaultdir = $shortstring . "|" . $hostname;
385 $onedir->{'defaultdir'} = $defaultdir;
388 if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
390 my $fontdefaultdir = "";
391 if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
393 if (( $fontdir eq $installer::globals
::fontsdirhostname
) && ( $fontdefaultdir eq $installer::globals
::fontsdirhostname
))
395 $installer::globals
::fontsdirname
= $onedir->{'defaultdir'};
396 $installer::globals
::fontsdirparent
= $onedir->{'uniqueparentname'};
401 ###############################################
402 # Fill content into the directory table
403 ###############################################
405 sub create_directorytable_from_collection
407 my ($directorytableref, $directoryref) = @_;
409 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
411 my $onedir = ${$directoryref}[$i];
412 my $hostname = $onedir->{'HostName'};
415 if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
417 if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; } # removing files from root directory
419 my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
421 push(@
{$directorytableref}, $oneline);
425 ###############################################
426 # Defining the root installation structure
427 ###############################################
429 sub add_root_directories
431 my ($directorytableref, $allvariableshashref, $onelanguage) = @_;
435 if (( ! $installer::globals
::languagepack
) && ( ! $installer::globals
::helppack
) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
439 $productname = $allvariableshashref->{'PRODUCTNAME'};
440 my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
441 my $baseproductversion = $productversion;
443 if (( $installer::globals
::prepare_winpatch
) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
445 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo
448 my $realproductkey = $productname . " " . $productversion;
449 my $productkey = $productname . " " . $baseproductversion;
451 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
453 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
454 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
456 if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
458 $productkey = $productname;
459 $realproductkey = $realproductname;
461 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
463 $productkey =~ s/\ /\_/g;
464 $realproductkey =~ s/\ /\_/g;
467 my $shortproductkey = installer
::windows
::idtglobal
::make_eight_three_conform
($productkey, "dir"); # third parameter not used
468 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline
470 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
471 push(@
{$directorytableref}, $oneline);
474 $oneline = "TARGETDIR\t\tSourceDir\n";
475 push(@
{$directorytableref}, $oneline);
477 $oneline = "WindowsFolder\tTARGETDIR\tWindows\n";
478 push(@
{$directorytableref}, $oneline);
480 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
481 push(@
{$directorytableref}, $oneline);
483 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
484 push(@
{$directorytableref}, $oneline);
486 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
487 push(@
{$directorytableref}, $oneline);
489 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
490 push(@
{$directorytableref}, $oneline);
492 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
493 push(@
{$directorytableref}, $oneline);
495 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
496 push(@
{$directorytableref}, $oneline);
498 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
499 push(@
{$directorytableref}, $oneline);
501 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
502 push(@
{$directorytableref}, $oneline);
504 if ( $installer::globals
::usesharepointpath
)
506 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
507 push(@
{$directorytableref}, $oneline);
510 my $localtemplatefoldername = $installer::globals
::templatefoldername
;
511 my $directorytableentry = $localtemplatefoldername;
512 my $shorttemplatefoldername = installer
::windows
::idtglobal
::make_eight_three_conform
($localtemplatefoldername, "dir");
513 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
514 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
515 push(@
{$directorytableref}, $oneline);
517 if ( $installer::globals
::fontsdirname
)
519 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
523 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
526 push(@
{$directorytableref}, $oneline);
530 ###############################################
531 # Creating the file Director.idt dynamically
532 ###############################################
534 sub create_directory_table
536 my ($directoryref, $languagesarrayref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
538 # Structure of the directory table:
539 # Directory Directory_Parent DefaultDir
540 # Directory is a unique identifier
541 # Directory_Parent is the unique identifier of the parent
542 # DefaultDir is .:APPLIC~1|Application Data with
543 # Before ":" : [sourcedir]:[destdir] (not programmed yet)
544 # After ":" : 8+3 and not 8+3 the destination directory name
546 for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ )
548 my $onelanguage = ${$languagesarrayref}[$m];
549 $installer::globals
::installlocationdirectoryset
= 0;
551 my @directorytable = ();
554 overwrite_programfilesfolder
($allvariableshashref);
555 create_unique_directorynames
($directoryref, $allvariableshashref);
556 $already_checked_the_frigging_directories_for_uniqueness++;
557 create_defaultdir_directorynames
($directoryref, $shortdirnamehashref); # only destdir!
558 set_installlocation_directory
($directoryref, $allvariableshashref);
559 installer
::windows
::idtglobal
::write_idt_header
(\
@directorytable, "directory");
560 add_root_directories
(\
@directorytable, $allvariableshashref, $onelanguage);
561 create_directorytable_from_collection
(\
@directorytable, $directoryref);
565 my $directorytablename = $basedir . $installer::globals
::separator
. "Director.idt" . "." . $onelanguage;
566 installer
::files
::save_file
($directorytablename ,\
@directorytable);
567 $infoline = "Created idt file: $directorytablename\n";
568 push(@installer::globals
::logfileinfo
, $infoline);