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 if ( $installer::globals::installlocationdirectory =~ /oracle_/i ) { $installer::globals::sundirexists = 1; } 273 } 274 275 # setting the sundirectory 276 if ( $styles =~ /\bSUNDIRECTORY\b/ ) 277 { 278 if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); } 279 $installer::globals::vendordirectory = $uniquename; 280 $installer::globals::vendordirectoryset = 1; 281 } 282 } 283} 284 285##################################################### 286# Adding ":." to selected default directory names 287##################################################### 288 289sub check_sourcedir_addon 290{ 291 my ( $onedir, $allvariableshashref ) = @_; 292 293 if (($installer::globals::addchildprojects) || 294 ($installer::globals::patch) || 295 ($installer::globals::languagepack) || 296 ($allvariableshashref->{'CHANGETARGETDIR'})) 297 { 298 my $sourcediraddon = "\:\."; 299 $onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon; 300 } 301 302} 303 304##################################################### 305# The directory with the style ISINSTALLLOCATION 306# will be replaced by INSTALLLOCATION 307##################################################### 308 309sub set_installlocation_directory 310{ 311 my ( $directoryref, $allvariableshashref ) = @_; 312 313 if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); } 314 315 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 316 { 317 my $onedir = ${$directoryref}[$i]; 318 319 if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory ) 320 { 321 $onedir->{'uniquename'} = "INSTALLLOCATION"; 322 check_sourcedir_addon($onedir, $allvariableshashref); 323 } 324 325 if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory ) 326 { 327 check_sourcedir_addon($onedir, $allvariableshashref); 328 } 329 330 if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory ) 331 { 332 $onedir->{'uniqueparentname'} = "INSTALLLOCATION"; 333 } 334 } 335} 336 337##################################################### 338# Getting the name of the top level directory. This 339# can have only one letter 340##################################################### 341 342sub get_last_directory_name 343{ 344 my ($completepathref) = @_; 345 346 if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ ) 347 { 348 $$completepathref = $1; 349 } 350} 351 352##################################################### 353# Creating the defaultdir for the file Director.idt 354##################################################### 355 356sub create_defaultdir_directorynames 357{ 358 my ($directoryref, $shortdirnamehashref) = @_; 359 360 my @shortnames = (); 361 if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); } 362 363 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 364 { 365 my $onedir = ${$directoryref}[$i]; 366 my $hostname = $onedir->{'HostName'}; 367 368 $hostname =~ s/\Q$installer::globals::separator\E\s*$//; 369 get_last_directory_name(\$hostname); 370 # installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname); # making program/classes to classes 371 my $uniquename = $onedir->{'uniquename'}; 372 my $shortstring; 373 if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) )) 374 { 375 $shortstring = $installer::globals::saved83dirmapping{$uniquename}; 376 } 377 else 378 { 379 $shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames); 380 } 381 382 my $defaultdir; 383 384 if ( $shortstring eq $hostname ) 385 { 386 $defaultdir = $hostname; 387 } 388 else 389 { 390 $defaultdir = $shortstring . "|" . $hostname; 391 } 392 393 $onedir->{'defaultdir'} = $defaultdir; 394 395 my $fontdir = ""; 396 if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; } 397 398 my $fontdefaultdir = ""; 399 if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; } 400 401 if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname )) 402 { 403 $installer::globals::fontsdirname = $onedir->{'defaultdir'}; 404 $installer::globals::fontsdirparent = $onedir->{'uniqueparentname'}; 405 } 406 } 407} 408 409############################################### 410# Fill content into the directory table 411############################################### 412 413sub create_directorytable_from_collection 414{ 415 my ($directorytableref, $directoryref) = @_; 416 417 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 418 { 419 my $onedir = ${$directoryref}[$i]; 420 my $hostname = $onedir->{'HostName'}; 421 my $dir = ""; 422 423 if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; } 424 425 if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; } # removing files from root directory 426 427 my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n"; 428 429 push(@{$directorytableref}, $oneline); 430 } 431} 432 433############################################### 434# Defining the root installation structure 435############################################### 436 437sub add_root_directories 438{ 439 my ($directorytableref, $allvariableshashref) = @_; 440 441# my $sourcediraddon = ""; 442# if (($installer::globals::addchildprojects) || 443# ($installer::globals::patch) || 444# ($installer::globals::languagepack) || 445# ($allvariableshashref->{'CHANGETARGETDIR'})) 446# { 447# $sourcediraddon = "\:\."; 448# } 449 450 my $oneline = ""; 451 452 if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} )) 453 { 454 my $productname = $allvariableshashref->{'PRODUCTNAME'}; 455 my $productversion = $allvariableshashref->{'PRODUCTVERSION'}; 456 my $baseproductversion = $productversion; 457 458 if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} )) 459 { 460 $baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'}; # for example "2.0" for OOo 461 } 462 463 my $realproductkey = $productname . " " . $productversion; 464 my $productkey = $productname . " " . $baseproductversion; 465 466 if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} )) 467 { 468 $productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 469 $realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'}; 470 } 471 if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} ) 472 { 473 $productkey = $productname; 474 $realproductkey = $realproductname; 475 } 476 if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} ) 477 { 478 $productkey =~ s/\ /\_/g; 479 $realproductkey =~ s/\ /\_/g; 480 } 481 482 my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir"); # third parameter not used 483 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline 484 485 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n"; 486 push(@{$directorytableref}, $oneline); 487 } 488 489 $oneline = "TARGETDIR\t\tSourceDir\n"; 490 push(@{$directorytableref}, $oneline); 491 492 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n"; 493 push(@{$directorytableref}, $oneline); 494 495 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n"; 496 push(@{$directorytableref}, $oneline); 497 498 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n"; 499 push(@{$directorytableref}, $oneline); 500 501 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n"; 502 push(@{$directorytableref}, $oneline); 503 504 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n"; 505 push(@{$directorytableref}, $oneline); 506 507 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n"; 508 push(@{$directorytableref}, $oneline); 509 510 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n"; 511 push(@{$directorytableref}, $oneline); 512 513 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n"; 514 push(@{$directorytableref}, $oneline); 515 516 if ( $installer::globals::usesharepointpath ) 517 { 518 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n"; 519 push(@{$directorytableref}, $oneline); 520 } 521 522 $oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n"; 523 push(@{$directorytableref}, $oneline); 524 525 my $localtemplatefoldername = $installer::globals::templatefoldername; 526 my $directorytableentry = $localtemplatefoldername; 527 my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir"); 528 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; } 529 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n"; 530 push(@{$directorytableref}, $oneline); 531 532 if ( $installer::globals::fontsdirname ) 533 { 534 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n"; 535 } 536 else 537 { 538 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n"; 539 } 540 541 push(@{$directorytableref}, $oneline); 542 543} 544 545############################################### 546# Creating the file Director.idt dynamically 547############################################### 548 549sub create_directory_table 550{ 551 my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_; 552 553 # Structure of the directory table: 554 # Directory Directory_Parent DefaultDir 555 # Directory is a unique identifier 556 # Directory_Parent is the unique identifier of the parent 557 # DefaultDir is .:APPLIC~1|Application Data with 558 # Before ":" : [sourcedir]:[destdir] (not programmed yet) 559 # After ":" : 8+3 and not 8+3 the destination directory name 560 561 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table start"); 562 563 my @directorytable = (); 564 my $infoline; 565 566 overwrite_programfilesfolder($allvariableshashref); 567 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); } 568 create_unique_directorynames($directoryref, $allvariableshashref); 569 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); } 570 create_defaultdir_directorynames($directoryref, $shortdirnamehashref); # only destdir! 571 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); } 572 set_installlocation_directory($directoryref, $allvariableshashref); 573 if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); } 574 installer::windows::idtglobal::write_idt_header(\@directorytable, "directory"); 575 add_root_directories(\@directorytable, $allvariableshashref); 576 create_directorytable_from_collection(\@directorytable, $directoryref); 577 578 # Saving the file 579 580 my $directorytablename = $basedir . $installer::globals::separator . "Director.idt"; 581 installer::files::save_file($directorytablename ,\@directorytable); 582 $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename); 583 584 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table end"); 585} 586 5871; 588