Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / solenv / bin / modules / installer / windows / directory.pm
blob829687e8b65c8b5e924f23ce0ed97fb003b02f13
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;
22 use installer::files;
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(
33 AdminToolsFolder
34 AppDataFolder
35 CommonAppDataFolder
36 CommonFiles64Folder
37 CommonFilesFolder
38 DesktopFolder
39 FavoritesFolder
40 FontsFolder
41 LocalAppDataFolder
42 MyPicturesFolder
43 NetHoodFolder
44 PersonalFolder
45 PrintHoodFolder
46 ProgramFiles64Folder
47 ProgramFilesFolder
48 ProgramMenuFolder
49 RecentFolder
50 SendToFolder
51 StartMenuFolder
52 StartupFolder
53 System16Folder
54 System64Folder
55 SystemFolder
56 TempFolder
57 TemplateFolder
58 WindowsFolder
59 WindowsVolume
62 sub collectdirectorytrees
64 my ( $directoryref ) = @_;
66 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
68 my $onedir = ${$directoryref}[$i];
69 my $styles = "";
70 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
72 if ( $styles ne "" )
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 = "";
111 my $cutlength = 60;
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 )
121 my $partstring = "";
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*\-//;
134 else
136 if ( length($onestring) > $length ) {
137 $partstring = substr($onestring, 0, $length);
139 else {
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;
161 return $shortstring;
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 = ();
177 my $infoline = "";
179 for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
181 my $onedir = ${$directoryref}[$i];
182 my $uniquename = $onedir->{'HostName'};
184 my $styles = "";
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;
226 my $keepparent = 1;
228 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator
230 $uniqueparentname = $1;
231 $keepparent = 0;
233 else
235 $uniqueparentname = $installer::globals::programfilesfolder;
236 $keepparent = 1;
239 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
241 $uniqueparentname = $installer::globals::programfilesfolder;
242 $keepparent = 1;
244 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
246 $uniqueparentname = $installer::globals::commonfilesfolder;
247 $keepparent = 1;
249 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
251 $uniqueparentname = $installer::globals::commonappdatafolder;
252 $keepparent = 1;
254 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
256 $uniqueparentname = $installer::globals::localappdatafolder;
257 $keepparent = 1;
260 if ( $styles =~ /\bSHAREPOINTPATH\b/ )
262 $uniqueparentname = "SHAREPOINTPATH";
263 $installer::globals::usesharepointpath = 1;
264 $keepparent = 1;
267 # also setting short directory name for the parent
269 my $originaluniqueparentname = $uniqueparentname;
271 if ( ! $keepparent )
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) = @_;
378 my @shortnames = ();
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'};
390 my $shortstring;
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};
399 else
401 $shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
404 my $defaultdir;
406 if ( $shortstring eq $hostname )
408 $defaultdir = $hostname;
410 else
412 $defaultdir = $shortstring . "|" . $hostname;
415 $onedir->{'defaultdir'} = $defaultdir;
417 my $fontdir = "";
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'};
443 my $dir = "";
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) = @_;
463 my $oneline = "";
465 if (( ! $installer::globals::languagepack ) && ( ! $installer::globals::helppack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
467 my $productname;
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";
551 else
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 = ();
582 my $infoline;
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);
593 # Saving the file
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 ################################################
606 sub starts_with
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");
626 ${$var} = $d;
627 return 1;
631 return 0;