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 my @msistandarddirectorynames = qw(
62 sub collectdirectorytrees
64 my ( $directoryref ) = @_;
66 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
68 my $onedir = ${$directoryref}[$i];
70 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
74 foreach my $treestyle ( keys %installer::globals
::treestyles
)
76 if ( $styles =~ /\b$treestyle\b/ )
78 my $hostname = $onedir->{'HostName'};
79 # -> hostname is the key, the style the value!
80 $installer::globals
::hostnametreestyles
{$hostname} = $treestyle;
87 ##############################################################
88 # Overwriting global programfilesfolder, if required
89 ##############################################################
91 sub overwrite_programfilesfolder
93 my ( $allvariables ) = @_;
95 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 ))
97 $installer::globals
::programfilesfolder
= "ProgramFiles64Folder";
101 ##############################################################
102 # Maximum length of directory name is 72.
103 # Taking care of underlines, which are the separator.
104 ##############################################################
106 sub make_short_dir_version
108 my ($longstring) = @_;
110 my $shortstring = "";
112 my $length = 5; # So the directory can still be recognized
113 my $longstring_save = $longstring;
115 # Splitting the string at each "underline" and allowing only
116 # $length characters per directory name.
117 # Checking also uniqueness and length.
119 for my $onestring ( split /_\s*/, $longstring )
123 if ( $onestring =~ /\-/ )
125 for my $onelocalstring ( split /-\s*/, $onestring )
127 if ( length($onelocalstring) > $length ) {
128 $onelocalstring = substr($onelocalstring, 0, $length);
130 $partstring .= "-" . $onelocalstring;
132 $partstring =~ s/^\s*\-//;
136 if ( length($onestring) > $length ) {
137 $partstring = substr($onestring, 0, $length);
140 $partstring = $onestring;
144 $shortstring .= "_" . $partstring;
147 $shortstring =~ s/^\s*\_//;
149 # Setting unique ID to each directory
150 # No counter allowed, process must be absolute reproducible due to patch creation process.
152 # chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`); # Very, very slow
153 # my $subid = substr($id, 0, 9); # taking only the first 9 digits
155 my $subid = installer
::windows
::msiglobal
::calculate_id
($longstring_save, 9); # taking only the first 9 digits
157 if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }
159 $shortstring = $shortstring . "_" . $subid;
164 ##############################################################
165 # Adding unique directory names to the directory collection
166 ##############################################################
168 my $already_checked_the_frigging_directories_for_uniqueness = 0;
170 sub create_unique_directorynames
172 my ($directoryref, $allvariables) = @_;
174 my %completedirhashstep1 = ();
175 my %shortdirhash = ();
176 my %shortdirhashreverse = ();
179 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
181 my $onedir = ${$directoryref}[$i];
182 my $uniquename = $onedir->{'HostName'};
185 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
187 $uniquename =~ s/^\s*//g; # removing beginning white spaces
188 $uniquename =~ s/\s*$//g; # removing ending white spaces
189 $uniquename =~ s/\s//g; # removing white spaces
190 $uniquename =~ s/\_//g; # removing existing underlines
191 $uniquename =~ s/\.//g; # removing dots in directoryname
192 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline
193 $uniquename =~ s/OpenOffice/OO/g;
194 $uniquename =~ s/LibreOffice/LO/g;
195 $uniquename =~ s/_registry/_rgy/g;
196 $uniquename =~ s/_registration/_rgn/g;
197 $uniquename =~ s/_extension/_ext/g;
198 $uniquename =~ s/_frame/_frm/g;
199 $uniquename =~ s/_table/_tbl/g;
200 $uniquename =~ s/_chart/_crt/g;
201 $uniquename =~ s/_plat-linux/_plx/g;
203 # The names after this small changes must still be unique!
204 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"); }
205 $completedirhashstep1{$uniquename} = 1;
207 # Starting to make unique name for the parent and its directory
208 my $originaluniquename = $uniquename;
210 $uniquename = make_short_dir_version
($uniquename);
212 # Checking if the same directory already exists, but has another short version.
213 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"); }
215 # Also checking vice versa
216 # Checking if the same short directory already exists, but has another long version.
217 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"); }
219 # Creating assignment from long to short directory names
220 $shortdirhash{$originaluniquename} = $uniquename;
221 $shortdirhashreverse{$uniquename} = $originaluniquename;
223 # Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).
225 my $uniqueparentname = $originaluniquename;
228 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator
230 $uniqueparentname = $1;
235 $uniqueparentname = $installer::globals
::programfilesfolder
;
239 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
241 $uniqueparentname = $installer::globals
::programfilesfolder
;
244 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
246 $uniqueparentname = $installer::globals
::commonfilesfolder
;
249 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
251 $uniqueparentname = $installer::globals
::commonappdatafolder
;
254 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
256 $uniqueparentname = $installer::globals
::localappdatafolder
;
260 if ( $styles =~ /\bSHAREPOINTPATH\b/ )
262 $uniqueparentname = "SHAREPOINTPATH";
263 $installer::globals
::usesharepointpath
= 1;
267 # also setting short directory name for the parent
269 my $originaluniqueparentname = $uniqueparentname;
273 $uniqueparentname = make_short_dir_version
($uniqueparentname);
276 # Again checking if the same directory already exists, but has another short version.
277 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"); }
279 # Also checking vice versa
280 # Checking if the same short directory already exists, but has another long version.
281 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"); }
283 $shortdirhash{$originaluniqueparentname} = $uniqueparentname;
284 $shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
286 # Hyphen not allowed in database
287 $uniquename =~ s/\-/\_/g; # making "-" to "_"
288 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_"
290 # And finally setting the values for the directories
291 $onedir->{'uniquename'} = $uniquename;
292 $onedir->{'uniqueparentname'} = $uniqueparentname;
294 # setting the installlocation directory
295 if ( $styles =~ /\bISINSTALLLOCATION\b/ )
297 if ( $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION already set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
298 $installer::globals
::installlocationdirectory
= $uniquename;
299 $installer::globals
::installlocationdirectoryset
= 1;
304 #####################################################
305 # Adding ":." to selected default directory names
306 #####################################################
308 sub check_sourcedir_addon
310 my ( $onedir, $allvariableshashref ) = @_;
312 if (($installer::globals
::languagepack
) ||
313 ($installer::globals
::helppack
) ||
314 ($allvariableshashref->{'CHANGETARGETDIR'}))
316 my $sourcediraddon = "\:\.";
317 $onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
322 #####################################################
323 # The directory with the style ISINSTALLLOCATION
324 # will be replaced by INSTALLLOCATION
325 #####################################################
327 sub set_installlocation_directory
329 my ( $directoryref, $allvariableshashref ) = @_;
331 if ( ! $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
333 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
335 my $onedir = ${$directoryref}[$i];
337 if ( $onedir->{'uniquename'} eq $installer::globals
::installlocationdirectory
)
339 $onedir->{'uniquename'} = "INSTALLLOCATION";
340 check_sourcedir_addon
($onedir, $allvariableshashref);
343 if ( $onedir->{'uniquename'} eq $installer::globals
::vendordirectory
)
345 check_sourcedir_addon
($onedir, $allvariableshashref);
348 if ( $onedir->{'uniqueparentname'} eq $installer::globals
::installlocationdirectory
)
350 $onedir->{'uniqueparentname'} = "INSTALLLOCATION";
355 #####################################################
356 # Getting the name of the top level directory. This
357 # can have only one letter
358 #####################################################
360 sub get_last_directory_name
362 my ($completepathref) = @_;
364 if ( $$completepathref =~ /^.*[\/\\](.+?
)\s
*$/ )
366 $$completepathref = $1;
370 #####################################################
371 # Creating the defaultdir for the file Director.idt
372 #####################################################
374 sub create_defaultdir_directorynames
376 my ($directoryref, $shortdirnamehashref) = @_;
379 if ( $installer::globals
::updatedatabase
) { @shortnames = values(%{$shortdirnamehashref}); }
380 elsif ( $installer::globals
::prepare_winpatch
) { @shortnames = values(%installer::globals
::saved83dirmapping
); }
382 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
384 my $onedir = ${$directoryref}[$i];
385 my $hostname = $onedir->{'HostName'};
387 $hostname =~ s/\Q$installer::globals::separator\E\s*$//;
388 get_last_directory_name
(\
$hostname);
389 my $uniquename = $onedir->{'uniquename'};
391 if (( $installer::globals
::updatedatabase
) && ( exists($shortdirnamehashref->{$uniquename}) ))
393 $shortstring = $shortdirnamehashref->{$uniquename};
395 elsif (( $installer::globals
::prepare_winpatch
) && ( exists($installer::globals
::saved83dirmapping
{$uniquename}) ))
397 $shortstring = $installer::globals
::saved83dirmapping
{$uniquename};
401 $shortstring = installer
::windows
::idtglobal
::make_eight_three_conform
($hostname, "dir", \
@shortnames);
406 if ( $shortstring eq $hostname )
408 $defaultdir = $hostname;
412 $defaultdir = $shortstring . "|" . $hostname;
415 $onedir->{'defaultdir'} = $defaultdir;
418 if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
420 my $fontdefaultdir = "";
421 if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
423 if (( $fontdir eq $installer::globals
::fontsdirhostname
) && ( $fontdefaultdir eq $installer::globals
::fontsdirhostname
))
425 $installer::globals
::fontsdirname
= $onedir->{'defaultdir'};
426 $installer::globals
::fontsdirparent
= $onedir->{'uniqueparentname'};
431 ###############################################
432 # Fill content into the directory table
433 ###############################################
435 sub create_directorytable_from_collection
437 my ($directorytableref, $directoryref) = @_;
439 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
441 my $onedir = ${$directoryref}[$i];
442 my $hostname = $onedir->{'HostName'};
445 if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
447 if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; } # removing files from root directory
449 my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
451 push(@
{$directorytableref}, $oneline);
455 ###############################################
456 # Defining the root installation structure
457 ###############################################
459 sub add_root_directories
461 my ($directorytableref, $allvariableshashref, $onelanguage) = @_;
465 if (( ! $installer::globals
::languagepack
) && ( ! $installer::globals
::helppack
) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
469 $productname = $allvariableshashref->{'PRODUCTNAME'};
470 my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
471 my $baseproductversion = $productversion;
473 if (( $installer::globals
::prepare_winpatch
) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
475 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo
478 my $realproductkey = $productname . " " . $productversion;
479 my $productkey = $productname . " " . $baseproductversion;
481 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
483 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
484 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
486 if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
488 $productkey = $productname;
489 $realproductkey = $realproductname;
491 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
493 $productkey =~ s/\ /\_/g;
494 $realproductkey =~ s/\ /\_/g;
497 my $shortproductkey = installer
::windows
::idtglobal
::make_eight_three_conform
($productkey, "dir"); # third parameter not used
498 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline
500 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
501 push(@
{$directorytableref}, $oneline);
504 $oneline = "TARGETDIR\t\tSourceDir\n";
505 push(@
{$directorytableref}, $oneline);
507 $oneline = "WindowsFolder\tTARGETDIR\tWindows\n";
508 push(@
{$directorytableref}, $oneline);
510 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
511 push(@
{$directorytableref}, $oneline);
513 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
514 push(@
{$directorytableref}, $oneline);
516 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
517 push(@
{$directorytableref}, $oneline);
519 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
520 push(@
{$directorytableref}, $oneline);
522 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
523 push(@
{$directorytableref}, $oneline);
525 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
526 push(@
{$directorytableref}, $oneline);
528 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
529 push(@
{$directorytableref}, $oneline);
531 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
532 push(@
{$directorytableref}, $oneline);
534 if ( $installer::globals
::usesharepointpath
)
536 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
537 push(@
{$directorytableref}, $oneline);
540 my $localtemplatefoldername = $installer::globals
::templatefoldername
;
541 my $directorytableentry = $localtemplatefoldername;
542 my $shorttemplatefoldername = installer
::windows
::idtglobal
::make_eight_three_conform
($localtemplatefoldername, "dir");
543 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
544 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
545 push(@
{$directorytableref}, $oneline);
547 if ( $installer::globals
::fontsdirname
)
549 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
553 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
556 push(@
{$directorytableref}, $oneline);
560 ###############################################
561 # Creating the file Director.idt dynamically
562 ###############################################
564 sub create_directory_table
566 my ($directoryref, $languagesarrayref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
568 # Structure of the directory table:
569 # Directory Directory_Parent DefaultDir
570 # Directory is a unique identifier
571 # Directory_Parent is the unique identifier of the parent
572 # DefaultDir is .:APPLIC~1|Application Data with
573 # Before ":" : [sourcedir]:[destdir] (not programmed yet)
574 # After ":" : 8+3 and not 8+3 the destination directory name
576 for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ )
578 my $onelanguage = ${$languagesarrayref}[$m];
579 $installer::globals
::installlocationdirectoryset
= 0;
581 my @directorytable = ();
584 overwrite_programfilesfolder
($allvariableshashref);
585 create_unique_directorynames
($directoryref, $allvariableshashref);
586 $already_checked_the_frigging_directories_for_uniqueness++;
587 create_defaultdir_directorynames
($directoryref, $shortdirnamehashref); # only destdir!
588 set_installlocation_directory
($directoryref, $allvariableshashref);
589 installer
::windows
::idtglobal
::write_idt_header
(\
@directorytable, "directory");
590 add_root_directories
(\
@directorytable, $allvariableshashref, $onelanguage);
591 create_directorytable_from_collection
(\
@directorytable, $directoryref);
595 my $directorytablename = $basedir . $installer::globals
::separator
. "Director.idt" . "." . $onelanguage;
596 installer
::files
::save_file
($directorytablename ,\
@directorytable);
597 $infoline = "Created idt file: $directorytablename\n";
598 push(@installer::globals
::logfileinfo
, $infoline);
602 ################################################
603 # Check if the string starts with another string
604 ################################################
608 my ($first, $second) = @_;
610 return substr($first, 0, length($second)) eq $second;
613 ###############################################
614 # Check if the directory prefix is a standard
615 # directory name. If it is the case, then the
616 # standard directory name is returned in $var.
617 ###############################################
619 sub has_standard_directory_prefix
621 my ($dir, $var) = @_;
623 for my $d (@msistandarddirectorynames) {
624 if (starts_with
($dir, $d) && $dir ne $d) {
625 installer
::logger
::print_message
("... match found: [$d]\n");