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
;
24 use installer
::exiter
;
26 use installer
::globals
;
27 use installer
::pathanalyzer
;
28 use installer
::windows
::idtglobal
;
29 use installer
::windows
::msiglobal
;
31 ##############################################################
32 # Collecting all directory trees in global hash
33 ##############################################################
35 my @msistandarddirectorynames = qw(
65 sub collectdirectorytrees
67 my ( $directoryref ) = @_;
69 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
71 my $onedir = ${$directoryref}[$i];
73 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
77 foreach my $treestyle ( keys %installer::globals
::treestyles
)
79 if ( $styles =~ /\b$treestyle\b/ )
81 my $hostname = $onedir->{'HostName'};
82 # -> hostname is the key, the style the value!
83 $installer::globals
::hostnametreestyles
{$hostname} = $treestyle;
90 ##############################################################
91 # Overwriting global programfilesfolder, if required
92 ##############################################################
94 sub overwrite_programfilesfolder
96 my ( $allvariables ) = @_;
98 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 ))
100 $installer::globals
::programfilesfolder
= "ProgramFiles64Folder";
104 ##############################################################
105 # Maximum length of directory name is 72.
106 # Taking care of underlines, which are the separator.
107 ##############################################################
109 sub make_short_dir_version
111 my ($longstring) = @_;
113 my $shortstring = "";
115 my $length = 5; # So the directory can still be recognized
116 my $longstring_save = $longstring;
118 # Splitting the string at each "underline" and allowing only
119 # $length characters per directory name.
120 # Checking also uniqueness and length.
122 for my $onestring ( split /_\s*/, $longstring )
126 if ( $onestring =~ /\-/ )
128 for my $onelocalstring ( split /-\s*/, $onestring )
130 if ( length($onelocalstring) > $length ) {
131 $onelocalstring = substr($onelocalstring, 0, $length);
133 $partstring .= "-" . $onelocalstring;
135 $partstring =~ s/^\s*\-//;
139 if ( length($onestring) > $length ) {
140 $partstring = substr($onestring, 0, $length);
143 $partstring = $onestring;
147 $shortstring .= "_" . $partstring;
150 $shortstring =~ s/^\s*\_//;
152 # Setting unique ID to each directory
153 # No counter allowed, process must be absolute reproducible due to patch creation process.
155 # chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`); # Very, very slow
156 # my $subid = substr($id, 0, 9); # taking only the first 9 digits
158 my $subid = installer
::windows
::msiglobal
::calculate_id
($longstring_save, 9); # taking only the first 9 digits
160 if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }
162 $shortstring = $shortstring . "_" . $subid;
167 ##############################################################
168 # Adding unique directory names to the directory collection
169 ##############################################################
171 my $already_checked_the_frigging_directories_for_uniqueness = 0;
173 sub create_unique_directorynames
175 my ($directoryref, $allvariables) = @_;
177 my %completedirhashstep1 = ();
178 my %shortdirhash = ();
179 my %shortdirhashreverse = ();
182 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
184 my $onedir = ${$directoryref}[$i];
185 my $uniquename = $onedir->{'HostName'};
188 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
190 $uniquename =~ s/^\s*//g; # removing beginning white spaces
191 $uniquename =~ s/\s*$//g; # removing ending white spaces
192 $uniquename =~ s/\s//g; # removing white spaces
193 $uniquename =~ s/\_//g; # removing existing underlines
194 $uniquename =~ s/\.//g; # removing dots in directoryname
195 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline
196 $uniquename =~ s/OpenOffice/OO/g;
197 $uniquename =~ s/LibreOffice/LO/g;
198 $uniquename =~ s/_registry/_rgy/g;
199 $uniquename =~ s/_registration/_rgn/g;
200 $uniquename =~ s/_extension/_ext/g;
201 $uniquename =~ s/_frame/_frm/g;
202 $uniquename =~ s/_table/_tbl/g;
203 $uniquename =~ s/_chart/_crt/g;
204 $uniquename =~ s/_plat-linux/_plx/g;
206 # The names after this small changes must still be unique!
207 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"); }
208 $completedirhashstep1{$uniquename} = 1;
210 # Starting to make unique name for the parent and its directory
211 my $originaluniquename = $uniquename;
213 $uniquename = make_short_dir_version
($uniquename);
215 # Checking if the same directory already exists, but has another short version.
216 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"); }
218 # Also checking vice versa
219 # Checking if the same short directory already exists, but has another long version.
220 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"); }
222 # Creating assignment from long to short directory names
223 $shortdirhash{$originaluniquename} = $uniquename;
224 $shortdirhashreverse{$uniquename} = $originaluniquename;
226 # Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).
228 my $uniqueparentname = $originaluniquename;
231 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator
233 $uniqueparentname = $1;
238 $uniqueparentname = $installer::globals
::programfilesfolder
;
242 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
244 $uniqueparentname = $installer::globals
::programfilesfolder
;
247 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
249 $uniqueparentname = $installer::globals
::commonfilesfolder
;
252 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
254 $uniqueparentname = $installer::globals
::commonappdatafolder
;
257 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
259 $uniqueparentname = $installer::globals
::localappdatafolder
;
263 if ( $styles =~ /\bSHAREPOINTPATH\b/ )
265 $uniqueparentname = "SHAREPOINTPATH";
266 $installer::globals
::usesharepointpath
= 1;
270 # also setting short directory name for the parent
272 my $originaluniqueparentname = $uniqueparentname;
276 $uniqueparentname = make_short_dir_version
($uniqueparentname);
279 # Again checking if the same directory already exists, but has another short version.
280 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"); }
282 # Also checking vice versa
283 # Checking if the same short directory already exists, but has another long version.
284 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"); }
286 $shortdirhash{$originaluniqueparentname} = $uniqueparentname;
287 $shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
289 # Hyphen not allowed in database
290 $uniquename =~ s/\-/\_/g; # making "-" to "_"
291 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_"
293 # And finally setting the values for the directories
294 $onedir->{'uniquename'} = $uniquename;
295 $onedir->{'uniqueparentname'} = $uniqueparentname;
297 # setting the installlocation directory
298 if ( $styles =~ /\bISINSTALLLOCATION\b/ )
300 if ( $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION already set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
301 $installer::globals
::installlocationdirectory
= $uniquename;
302 $installer::globals
::installlocationdirectoryset
= 1;
307 #####################################################
308 # Adding ":." to selected default directory names
309 #####################################################
311 sub check_sourcedir_addon
313 my ( $onedir, $allvariableshashref ) = @_;
315 if (($installer::globals
::languagepack
) ||
316 ($installer::globals
::helppack
) ||
317 ($allvariableshashref->{'CHANGETARGETDIR'}))
319 my $sourcediraddon = "\:\.";
320 $onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
325 #####################################################
326 # The directory with the style ISINSTALLLOCATION
327 # will be replaced by INSTALLLOCATION
328 #####################################################
330 sub set_installlocation_directory
332 my ( $directoryref, $allvariableshashref ) = @_;
334 if ( ! $installer::globals
::installlocationdirectoryset
) { installer
::exiter
::exit_program
("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
336 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
338 my $onedir = ${$directoryref}[$i];
340 if ( $onedir->{'uniquename'} eq $installer::globals
::installlocationdirectory
)
342 $onedir->{'uniquename'} = "INSTALLLOCATION";
343 check_sourcedir_addon
($onedir, $allvariableshashref);
346 if ( $onedir->{'uniquename'} eq $installer::globals
::vendordirectory
)
348 check_sourcedir_addon
($onedir, $allvariableshashref);
351 if ( $onedir->{'uniqueparentname'} eq $installer::globals
::installlocationdirectory
)
353 $onedir->{'uniqueparentname'} = "INSTALLLOCATION";
358 #####################################################
359 # Getting the name of the top level directory. This
360 # can have only one letter
361 #####################################################
363 sub get_last_directory_name
365 my ($completepathref) = @_;
367 if ( $$completepathref =~ /^.*[\/\\](.+?
)\s
*$/ )
369 $$completepathref = $1;
373 #####################################################
374 # Creating the defaultdir for the file Director.idt
375 #####################################################
377 sub create_defaultdir_directorynames
379 my ($directoryref, $shortdirnamehashref) = @_;
382 if ( $installer::globals
::updatedatabase
) { @shortnames = values(%{$shortdirnamehashref}); }
383 elsif ( $installer::globals
::prepare_winpatch
) { @shortnames = values(%installer::globals
::saved83dirmapping
); }
385 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
387 my $onedir = ${$directoryref}[$i];
388 my $hostname = $onedir->{'HostName'};
390 $hostname =~ s/\Q$installer::globals::separator\E\s*$//;
391 get_last_directory_name
(\
$hostname);
392 my $uniquename = $onedir->{'uniquename'};
394 if (( $installer::globals
::updatedatabase
) && ( exists($shortdirnamehashref->{$uniquename}) ))
396 $shortstring = $shortdirnamehashref->{$uniquename};
398 elsif (( $installer::globals
::prepare_winpatch
) && ( exists($installer::globals
::saved83dirmapping
{$uniquename}) ))
400 $shortstring = $installer::globals
::saved83dirmapping
{$uniquename};
404 $shortstring = installer
::windows
::idtglobal
::make_eight_three_conform
($hostname, "dir", \
@shortnames);
409 if ( $shortstring eq $hostname )
411 $defaultdir = $hostname;
415 $defaultdir = $shortstring . "|" . $hostname;
418 $onedir->{'defaultdir'} = $defaultdir;
421 if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
423 my $fontdefaultdir = "";
424 if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
426 if (( $fontdir eq $installer::globals
::fontsdirhostname
) && ( $fontdefaultdir eq $installer::globals
::fontsdirhostname
))
428 $installer::globals
::fontsdirname
= $onedir->{'defaultdir'};
429 $installer::globals
::fontsdirparent
= $onedir->{'uniqueparentname'};
434 ###############################################
435 # Fill content into the directory table
436 ###############################################
438 sub create_directorytable_from_collection
440 my ($directorytableref, $directoryref) = @_;
442 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
444 my $onedir = ${$directoryref}[$i];
445 my $hostname = $onedir->{'HostName'};
448 if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
450 if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; } # removing files from root directory
452 my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
454 push(@
{$directorytableref}, $oneline);
458 ###############################################
459 # Defining the root installation structure
460 ###############################################
462 sub add_root_directories
464 my ($directorytableref, $allvariableshashref, $onelanguage) = @_;
468 if (( ! $installer::globals
::languagepack
) && ( ! $installer::globals
::helppack
) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
472 $productname = $allvariableshashref->{'PRODUCTNAME'};
473 my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
474 my $baseproductversion = $productversion;
476 if (( $installer::globals
::prepare_winpatch
) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
478 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo
481 my $realproductkey = $productname;
482 my $productkey = $productname . " " . $baseproductversion;
484 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
486 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
487 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
489 if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
491 $productkey = $productname;
492 $realproductkey = $productname;
494 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
496 $productkey =~ s/\ /\_/g;
497 $realproductkey =~ s/\ /\_/g;
500 my $shortproductkey = installer
::windows
::idtglobal
::make_eight_three_conform
($productkey, "dir"); # third parameter not used
501 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline
503 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
504 push(@
{$directorytableref}, $oneline);
507 $oneline = "TARGETDIR\t\tSourceDir\n";
508 push(@
{$directorytableref}, $oneline);
510 $oneline = "WindowsFolder\tTARGETDIR\tWindows\n";
511 push(@
{$directorytableref}, $oneline);
513 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
514 push(@
{$directorytableref}, $oneline);
516 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
517 push(@
{$directorytableref}, $oneline);
519 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
520 push(@
{$directorytableref}, $oneline);
522 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
523 push(@
{$directorytableref}, $oneline);
525 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
526 push(@
{$directorytableref}, $oneline);
528 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
529 push(@
{$directorytableref}, $oneline);
531 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
532 push(@
{$directorytableref}, $oneline);
534 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
535 push(@
{$directorytableref}, $oneline);
537 if ( $installer::globals
::usesharepointpath
)
539 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
540 push(@
{$directorytableref}, $oneline);
543 my $localtemplatefoldername = $installer::globals
::templatefoldername
;
544 my $directorytableentry = $localtemplatefoldername;
545 my $shorttemplatefoldername = installer
::windows
::idtglobal
::make_eight_three_conform
($localtemplatefoldername, "dir");
546 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
547 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
548 push(@
{$directorytableref}, $oneline);
550 if ( $installer::globals
::fontsdirname
)
552 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
556 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
559 push(@
{$directorytableref}, $oneline);
563 ###############################################
564 # Creating the file Director.idt dynamically
565 ###############################################
567 sub create_directory_table
569 my ($directoryref, $languagesarrayref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
571 # Structure of the directory table:
572 # Directory Directory_Parent DefaultDir
573 # Directory is a unique identifier
574 # Directory_Parent is the unique identifier of the parent
575 # DefaultDir is .:APPLIC~1|Application Data with
576 # Before ":" : [sourcedir]:[destdir] (not programmed yet)
577 # After ":" : 8+3 and not 8+3 the destination directory name
579 for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ )
581 my $onelanguage = ${$languagesarrayref}[$m];
582 $installer::globals
::installlocationdirectoryset
= 0;
584 my @directorytable = ();
587 overwrite_programfilesfolder
($allvariableshashref);
588 create_unique_directorynames
($directoryref, $allvariableshashref);
589 $already_checked_the_frigging_directories_for_uniqueness++;
590 create_defaultdir_directorynames
($directoryref, $shortdirnamehashref); # only destdir!
591 set_installlocation_directory
($directoryref, $allvariableshashref);
592 installer
::windows
::idtglobal
::write_idt_header
(\
@directorytable, "directory");
593 add_root_directories
(\
@directorytable, $allvariableshashref, $onelanguage);
594 create_directorytable_from_collection
(\
@directorytable, $directoryref);
598 my $directorytablename = $basedir . $installer::globals
::separator
. "Director.idt" . "." . $onelanguage;
599 installer
::files
::save_file
($directorytablename ,\
@directorytable);
600 $infoline = "Created idt file: $directorytablename\n";
601 push(@installer::globals
::logfileinfo
, $infoline);
605 ################################################
606 # Check if the string starts with another string
607 ################################################
611 my ($first, $second) = @_;
613 return substr($first, 0, length($second)) eq $second;
616 ###############################################
617 # Check if the directory prefix is a standard
618 # directory name. If it is the case, then the
619 # standard directory name is returned in $var.
620 ###############################################
622 sub has_standard_directory_prefix
624 my ($dir, $var) = @_;
626 for my $d (@msistandarddirectorynames) {
627 if (starts_with
($dir, $d) && $dir ne $d) {
628 installer
::logger
::print_message
("... match found: [$d]\n");