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; 32 33############################################################## 34# Collecting all directory trees in global hash 35############################################################## 36 37sub collectdirectorytrees 38{ 39 my ( $directoryref ) = @_; 40 41 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 42 { 43 my $onedir = ${$directoryref}[$i]; 44 my $styles = ""; 45 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; } 46 47 if ( $styles ne "" ) 48 { 49 foreach my $treestyle ( keys %installer::globals::treestyles ) 50 { 51 if ( $styles =~ /\b$treestyle\b/ ) 52 { 53 my $hostname = $onedir->{'HostName'}; 54 # -> hostname is the key, the style the value! 55 $installer::globals::hostnametreestyles{$hostname} = $treestyle; 56 } 57 } 58 } 59 } 60} 61 62############################################################## 63# Overwriting global programfilesfolder, if required 64############################################################## 65 66sub overwrite_programfilesfolder 67{ 68 my ( $allvariables ) = @_; 69 70 if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} ) 71 { 72 $installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'}; 73 } 74} 75 76############################################################## 77# Maximum length of directory name is 72. 78# Taking care of underlines, which are the separator. 79############################################################## 80 81sub make_short_dir_version 82{ 83 my ($longstring) = @_; 84 85 my $shortstring = ""; 86 my $cutlength = 60; 87 my $length = 5; # So the directory can still be recognized 88 my $longstring_save = $longstring; 89 90 # Splitting the string at each "underline" and allowing only $length characters per directory name. 91 # Checking also uniqueness and length. 92 93 my $stringarray = installer::converter::convert_stringlist_into_array_without_newline(\$longstring, "_"); 94 95 foreach my $onestring ( @{$stringarray} ) 96 { 97 my $partstring = ""; 98 99 if ( $onestring =~ /\-/ ) 100 { 101 my $localstringarray = installer::converter::convert_stringlist_into_array_without_newline(\$onestring, "-"); 102 foreach my $onelocalstring ( @{$localstringarray} ) 103 { 104 if ( length($onelocalstring) > $length ) { $onelocalstring = substr($onelocalstring, 0, $length); } 105 $partstring = $partstring . "-" . $onelocalstring; 106 } 107 $partstring =~ s/^\s*\-//; 108 } 109 else 110 { 111 if ( length($onestring) > $length ) { $partstring = substr($onestring, 0, $length); } 112 else { $partstring = $onestring; } 113 } 114 115 $shortstring = $shortstring . "_" . $partstring; 116 } 117 118 $shortstring =~ s/^\s*\_//; 119 120 # Setting unique ID to each directory 121 # No counter allowed, process must be absolute reproducable due to patch creation process. 122 123 # chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`); # Very, very slow 124 # my $subid = substr($id, 0, 9); # taking only the first 9 digits 125 126 my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits 127 128 if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); } 129 130 $shortstring = $shortstring . "_" . $subid; 131 132 return $shortstring; 133} 134 135############################################################## 136# Adding unique directory names to the directory collection 137############################################################## 138 139sub create_unique_directorynames 140{ 141 my ($directoryref, $allvariables) = @_; 142 143 $installer::globals::officeinstalldirectoryset = 0; 144 145 my %completedirhashstep1 = (); 146 my %shortdirhash = (); 147 my %shortdirhashreverse = (); 148 my $infoline = ""; 149 my $errorcount = 0; 150 151 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 152 { 153 my $onedir = ${$directoryref}[$i]; 154 my $uniquename = $onedir->{'HostName'}; 155 156 my $styles = ""; 157 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; } 158 159 $uniquename =~ s/^\s*//g; # removing beginning white spaces 160 $uniquename =~ s/\s*$//g; # removing ending white spaces 161 $uniquename =~ s/\s//g; # removing white spaces 162 $uniquename =~ s/\_//g; # removing existing underlines 163 $uniquename =~ s/\.//g; # removing dots in directoryname 164 $uniquename =~ s/OpenOffice/OO/g; 165 166 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline 167 168 $uniquename =~ s/_registry/_rgy/g; 169 $uniquename =~ s/_registration/_rgn/g; 170 $uniquename =~ s/_extension/_ext/g; 171 $uniquename =~ s/_frame/_frm/g; 172 $uniquename =~ s/_table/_tbl/g; 173 $uniquename =~ s/_chart/_crt/g; 174 175 # The names after this small changes must still be unique! 176 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"); } 177 $completedirhashstep1{$uniquename} = 1; 178 179 # Starting to make unique name for the parent and its directory 180 my $originaluniquename = $uniquename; 181 182 $uniquename = make_short_dir_version($uniquename); 183 184 # Checking if the same directory already exists, but has another short version. 185 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"); } 186 187 # Also checking vice versa 188 # Checking if the same short directory already exists, but has another long version. 189 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"); } 190 191 # Creating assignment from long to short directory names 192 $shortdirhash{$originaluniquename} = $uniquename; 193 $shortdirhashreverse{$uniquename} = $originaluniquename; 194 195 # Important: The unique parent is generated from the string $originaluniquename (with the use of underlines). 196 197 my $uniqueparentname = $originaluniquename; 198 my $keepparent = 1; 199 200 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator 201 { 202 $uniqueparentname = $1; 203 $keepparent = 0; 204 } 205 else 206 { 207 $uniqueparentname = $installer::globals::programfilesfolder; 208 $keepparent = 1; 209 } 210 211 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ ) 212 { 213 $uniqueparentname = $installer::globals::programfilesfolder; 214 $keepparent = 1; 215 } 216 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ ) 217 { 218 $uniqueparentname = $installer::globals::commonfilesfolder; 219 $keepparent = 1; 220 } 221 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ ) 222 { 223 $uniqueparentname = $installer::globals::commonappdatafolder; 224 $keepparent = 1; 225 } 226 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ ) 227 { 228 $uniqueparentname = $installer::globals::localappdatafolder; 229 $keepparent = 1; 230 } 231 232 if ( $styles =~ /\bSHAREPOINTPATH\b/ ) 233 { 234 $uniqueparentname = "SHAREPOINTPATH"; 235 $installer::globals::usesharepointpath = 1; 236 $keepparent = 1; 237 } 238 239 # also setting short directory name for the parent 240 241 my $originaluniqueparentname = $uniqueparentname; 242 243 if ( ! $keepparent ) 244 { 245 $uniqueparentname = make_short_dir_version($uniqueparentname); 246 } 247 248 # Again checking if the same directory already exists, but has another short version. 249 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"); } 250 251 # Also checking vice versa 252 # Checking if the same short directory already exists, but has another long version. 253 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"); } 254 255 $shortdirhash{$originaluniqueparentname} = $uniqueparentname; 256 $shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname; 257 258 # Hyphen not allowed in database 259 $uniquename =~ s/\-/\_/g; # making "-" to "_" 260 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_" 261 262 # And finally setting the values for the directories 263 $onedir->{'uniquename'} = $uniquename; 264 $onedir->{'uniqueparentname'} = $uniqueparentname; 265 266 # setting the installlocation directory 267 if ( $styles =~ /\bISINSTALLLOCATION\b/ ) 268 { 269 if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); } 270 $installer::globals::installlocationdirectory = $uniquename; 271 $installer::globals::installlocationdirectoryset = 1; 272 } 273 274 # setting the sundirectory 275 if ( $styles =~ /\bSUNDIRECTORY\b/ ) 276 { 277 if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); } 278 $installer::globals::vendordirectory = $uniquename; 279 $installer::globals::vendordirectoryset = 1; 280 } 281 } 282} 283 284##################################################### 285# Adding ":." to selected default directory names 286##################################################### 287 288sub check_sourcedir_addon 289{ 290 my ( $onedir, $allvariableshashref ) = @_; 291 292 if (($installer::globals::addchildprojects) || 293 ($installer::globals::patch) || 294 ($installer::globals::languagepack) || 295 ($allvariableshashref->{'CHANGETARGETDIR'})) 296 { 297 my $sourcediraddon = "\:\."; 298 $onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon; 299 } 300 301} 302 303##################################################### 304# The directory with the style ISINSTALLLOCATION 305# will be replaced by INSTALLLOCATION 306##################################################### 307 308sub set_installlocation_directory 309{ 310 my ( $directoryref, $allvariableshashref ) = @_; 311 312 if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); } 313 314 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 315 { 316 my $onedir = ${$directoryref}[$i]; 317 318 if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory ) 319 { 320 $onedir->{'uniquename'} = "INSTALLLOCATION"; 321 check_sourcedir_addon($onedir, $allvariableshashref); 322 } 323 324 if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory ) 325 { 326 check_sourcedir_addon($onedir, $allvariableshashref); 327 } 328 329 if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory ) 330 { 331 $onedir->{'uniqueparentname'} = "INSTALLLOCATION"; 332 } 333 } 334} 335 336##################################################### 337# Getting the name of the top level directory. This 338# can have only one letter 339##################################################### 340 341sub get_last_directory_name 342{ 343 my ($completepathref) = @_; 344 345 if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ ) 346 { 347 $$completepathref = $1; 348 } 349} 350 351##################################################### 352# Creating the defaultdir for the file Director.idt 353##################################################### 354 355sub create_defaultdir_directorynames 356{ 357 my ($directoryref, $shortdirnamehashref) = @_; 358 359 my @shortnames = (); 360 if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); } 361 362 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 363 { 364 my $onedir = ${$directoryref}[$i]; 365 my $hostname = $onedir->{'HostName'}; 366 367 $hostname =~ s/\Q$installer::globals::separator\E\s*$//; 368 get_last_directory_name(\$hostname); 369 # installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname); # making program/classes to classes 370 my $uniquename = $onedir->{'uniquename'}; 371 my $shortstring; 372 if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) )) 373 { 374 $shortstring = $installer::globals::saved83dirmapping{$uniquename}; 375 } 376 else 377 { 378 $shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames); 379 } 380 381 my $defaultdir; 382 383 if ( $shortstring eq $hostname ) 384 { 385 $defaultdir = $hostname; 386 } 387 else 388 { 389 $defaultdir = $shortstring . "|" . $hostname; 390 } 391 392 $onedir->{'defaultdir'} = $defaultdir; 393 394 my $fontdir = ""; 395 if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; } 396 397 my $fontdefaultdir = ""; 398 if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; } 399 400 if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname )) 401 { 402 $installer::globals::fontsdirname = $onedir->{'defaultdir'}; 403 $installer::globals::fontsdirparent = $onedir->{'uniqueparentname'}; 404 } 405 } 406} 407 408############################################### 409# Fill content into the directory table 410############################################### 411 412sub create_directorytable_from_collection 413{ 414 my ($directorytableref, $directoryref) = @_; 415 416 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 417 { 418 my $onedir = ${$directoryref}[$i]; 419 my $hostname = $onedir->{'HostName'}; 420 my $dir = ""; 421 422 if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; } 423 424 if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; } # removing files from root directory 425 426 my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n"; 427 428 push(@{$directorytableref}, $oneline); 429 } 430} 431 432############################################### 433# Defining the root installation structure 434############################################### 435 436sub add_root_directories 437{ 438 my ($directorytableref, $allvariableshashref) = @_; 439 440# my $sourcediraddon = ""; 441# if (($installer::globals::addchildprojects) || 442# ($installer::globals::patch) || 443# ($installer::globals::languagepack) || 444# ($allvariableshashref->{'CHANGETARGETDIR'})) 445# { 446# $sourcediraddon = "\:\."; 447# } 448 449 my $oneline = ""; 450 451 if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} )) 452 { 453 my $productname = $allvariableshashref->{'PRODUCTNAME'}; 454 my $productversion = $allvariableshashref->{'PRODUCTVERSION'}; 455 my $baseproductversion = $productversion; 456 457 if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} )) 458 { 459 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo 460 } 461 462 my $realproductkey = $productname . " " . $productversion; 463 my $productkey = $productname . " " . $baseproductversion; 464 465 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} )) 466 { 467 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 468 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 469 } 470 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} ) 471 { 472 $productkey =~ s/\ /\_/g; 473 $realproductkey =~ s/\ /\_/g; 474 } 475 476 my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir"); # third parameter not used 477 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline 478 479 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n"; 480 push(@{$directorytableref}, $oneline); 481 } 482 483 $oneline = "TARGETDIR\t\tSourceDir\n"; 484 push(@{$directorytableref}, $oneline); 485 486 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n"; 487 push(@{$directorytableref}, $oneline); 488 489 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n"; 490 push(@{$directorytableref}, $oneline); 491 492 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n"; 493 push(@{$directorytableref}, $oneline); 494 495 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n"; 496 push(@{$directorytableref}, $oneline); 497 498 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n"; 499 push(@{$directorytableref}, $oneline); 500 501 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n"; 502 push(@{$directorytableref}, $oneline); 503 504 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n"; 505 push(@{$directorytableref}, $oneline); 506 507 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n"; 508 push(@{$directorytableref}, $oneline); 509 510 if ( $installer::globals::usesharepointpath ) 511 { 512 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n"; 513 push(@{$directorytableref}, $oneline); 514 } 515 516 $oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n"; 517 push(@{$directorytableref}, $oneline); 518 519 my $localtemplatefoldername = $installer::globals::templatefoldername; 520 my $directorytableentry = $localtemplatefoldername; 521 my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir"); 522 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; } 523 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n"; 524 push(@{$directorytableref}, $oneline); 525 526 if ( $installer::globals::fontsdirname ) 527 { 528 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n"; 529 } 530 else 531 { 532 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n"; 533 } 534 535 push(@{$directorytableref}, $oneline); 536 537} 538 539############################################### 540# Creating the file Director.idt dynamically 541############################################### 542 543sub create_directory_table 544{ 545 my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_; 546 547 # Structure of the directory table: 548 # Directory Directory_Parent DefaultDir 549 # Directory is a unique identifier 550 # Directory_Parent is the unique identifier of the parent 551 # DefaultDir is .:APPLIC~1|Application Data with 552 # Before ":" : [sourcedir]:[destdir] (not programmed yet) 553 # After ":" : 8+3 and not 8+3 the destination directory name 554 555 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table start"); 556 557 my @directorytable = (); 558 my $infoline; 559 560 overwrite_programfilesfolder($allvariableshashref); 561 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); } 562 create_unique_directorynames($directoryref, $allvariableshashref); 563 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); } 564 create_defaultdir_directorynames($directoryref, $shortdirnamehashref); # only destdir! 565 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); } 566 set_installlocation_directory($directoryref, $allvariableshashref); 567 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); } 568 installer::windows::idtglobal::write_idt_header(\@directorytable, "directory"); 569 add_root_directories(\@directorytable, $allvariableshashref); 570 create_directorytable_from_collection(\@directorytable, $directoryref); 571 572 # Saving the file 573 574 my $directorytablename = $basedir . $installer::globals::separator . "Director.idt"; 575 installer::files::save_file($directorytablename ,\@directorytable); 576 $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename); 577 578 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table end"); 579} 580 5811; 582