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 33use strict; 34 35############################################################## 36# Collecting all directory trees in global hash 37############################################################## 38 39sub collectdirectorytrees 40{ 41 my ( $directoryref ) = @_; 42 43 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 44 { 45 my $onedir = ${$directoryref}[$i]; 46 my $styles = ""; 47 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; } 48 49 if ( $styles ne "" ) 50 { 51 foreach my $treestyle ( keys %installer::globals::treestyles ) 52 { 53 if ( $styles =~ /\b$treestyle\b/ ) 54 { 55 my $hostname = $onedir->{'HostName'}; 56 # -> hostname is the key, the style the value! 57 $installer::globals::hostnametreestyles{$hostname} = $treestyle; 58 } 59 } 60 } 61 } 62} 63 64############################################################## 65# Overwriting global programfilesfolder, if required 66############################################################## 67 68sub overwrite_programfilesfolder 69{ 70 my ( $allvariables ) = @_; 71 72 if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} ) 73 { 74 $installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'}; 75 } 76} 77 78 79 80 81=head2 make_short_dir_version($longstring) 82 83 Transform the given string into one that is at most 70 characters long. 84 That is done in two steps: 85 - Cut all parts separated by '_' or '-' down to a length of 5. 86 - Cut down the result to a length of 60 and fill it up to length 70 87 with the MD5 checksum. 88 89 This transform always returns the same result for the same string. 90 There is no counter and reference to a global set of names to make the string unique. 91 92=cut 93sub make_short_dir_version ($) 94{ 95 my ($longstring) = @_; 96 97 my $shortstring = ""; 98 my $cutlength = 60; 99 my $length = 5; # So the directory can still be recognized 100 my $longstring_save = $longstring; 101 102 # Splitting the string at each "underline" and allowing only $length characters per directory name. 103 # Checking also uniqueness and length. 104 105 my @outer_parts = split(/_/, $longstring); 106 foreach my $onestring (@outer_parts) 107 { 108 my $partstring = ""; 109 110 if ( $onestring =~ /\-/ ) 111 { 112 my @inner_parts = split(/-/, $onestring); 113 @inner_parts = map {substr($_,0,$length)} @inner_parts; 114 $partstring = join("-", @inner_parts); 115 $partstring =~ s/^\s*\-//; 116 } 117 else 118 { 119 $partstring = substr($onestring, 0, $length); 120 } 121 122 $shortstring .= "_" . $partstring; 123 } 124 125 $shortstring =~ s/^\s*\_//; 126 127 # Setting unique ID to each directory 128 # No counter allowed, process must be absolute reproducable due to patch creation process. 129 130 my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits 131 $shortstring = substr($shortstring, 0, $cutlength) . "_" . $subid; 132 133 return $shortstring; 134} 135 136############################################################## 137# Adding unique directory names to the directory collection 138############################################################## 139 140sub create_unique_directorynames 141{ 142 my ($directoryref, $allvariables) = @_; 143 144 $installer::globals::officeinstalldirectoryset = 0; 145 146 my %completedirhashstep1 = (); 147 my %shortdirhash = (); 148 my %shortdirhashreverse = (); 149 my $infoline = ""; 150 my $errorcount = 0; 151 152 for ( my $i = 0; $i <= $#{$directoryref}; $i++ ) 153 { 154 my $onedir = ${$directoryref}[$i]; 155 my $uniquename = $onedir->{'HostName'}; 156 157 my $styles = ""; 158 if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; } 159 160 $uniquename =~ s/^\s*//g; # removing beginning white spaces 161 $uniquename =~ s/\s*$//g; # removing ending white spaces 162 $uniquename =~ s/\s//g; # removing white spaces 163 $uniquename =~ s/\_//g; # removing existing underlines 164 $uniquename =~ s/\.//g; # removing dots in directoryname 165 $uniquename =~ s/OpenOffice/OO/g; 166 167 $uniquename =~ s/\Q$installer::globals::separator\E/\_/g; # replacing slash and backslash with underline 168 169 $uniquename =~ s/_registry/_rgy/g; 170 $uniquename =~ s/_registration/_rgn/g; 171 $uniquename =~ s/_extension/_ext/g; 172 $uniquename =~ s/_frame/_frm/g; 173 $uniquename =~ s/_table/_tbl/g; 174 $uniquename =~ s/_chart/_crt/g; 175 176 # The names after this small changes must still be unique! 177 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"); } 178 $completedirhashstep1{$uniquename} = 1; 179 180 # Starting to make unique name for the parent and its directory 181 my $originaluniquename = $uniquename; 182 183 $uniquename = make_short_dir_version($uniquename); 184 185 # Checking if the same directory already exists, but has another short version. 186 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"); } 187 188 # Also checking vice versa 189 # Checking if the same short directory already exists, but has another long version. 190 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"); } 191 192 # Creating assignment from long to short directory names 193 $shortdirhash{$originaluniquename} = $uniquename; 194 $shortdirhashreverse{$uniquename} = $originaluniquename; 195 196 # Important: The unique parent is generated from the string $originaluniquename (with the use of underlines). 197 198 my $uniqueparentname = $originaluniquename; 199 my $keepparent = 1; 200 201 if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ ) # the underline is now the separator 202 { 203 $uniqueparentname = $1; 204 $keepparent = 0; 205 } 206 else 207 { 208 $uniqueparentname = $installer::globals::programfilesfolder; 209 $keepparent = 1; 210 } 211 212 if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ ) 213 { 214 $uniqueparentname = $installer::globals::programfilesfolder; 215 $keepparent = 1; 216 } 217 if ( $styles =~ /\bCOMMONFILESFOLDER\b/ ) 218 { 219 $uniqueparentname = $installer::globals::commonfilesfolder; 220 $keepparent = 1; 221 } 222 if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ ) 223 { 224 $uniqueparentname = $installer::globals::commonappdatafolder; 225 $keepparent = 1; 226 } 227 if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ ) 228 { 229 $uniqueparentname = $installer::globals::localappdatafolder; 230 $keepparent = 1; 231 } 232 233 if ( $styles =~ /\bSHAREPOINTPATH\b/ ) 234 { 235 $uniqueparentname = "SHAREPOINTPATH"; 236 $installer::globals::usesharepointpath = 1; 237 $keepparent = 1; 238 } 239 240 # also setting short directory name for the parent 241 242 my $originaluniqueparentname = $uniqueparentname; 243 244 if ( ! $keepparent ) 245 { 246 $uniqueparentname = make_short_dir_version($uniqueparentname); 247 } 248 249 # Again checking if the same directory already exists, but has another short version. 250 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"); } 251 252 # Also checking vice versa 253 # Checking if the same short directory already exists, but has another long version. 254 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"); } 255 256 $shortdirhash{$originaluniqueparentname} = $uniqueparentname; 257 $shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname; 258 259 # Hyphen not allowed in database 260 $uniquename =~ s/\-/\_/g; # making "-" to "_" 261 $uniqueparentname =~ s/\-/\_/g; # making "-" to "_" 262 263 # And finally setting the values for the directories 264 $onedir->{'uniquename'} = $uniquename; 265 $onedir->{'uniqueparentname'} = $uniqueparentname; 266 267 # setting the installlocation directory 268 if ( $styles =~ /\bISINSTALLLOCATION\b/ ) 269 { 270 if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); } 271 $installer::globals::installlocationdirectory = $uniquename; 272 $installer::globals::installlocationdirectoryset = 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) = @_; 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->{'NOSPACEINDIRECTORYNAME'} ) 472 { 473 $productkey =~ s/\ /\_/g; 474 $realproductkey =~ s/\ /\_/g; 475 } 476 477 my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir"); # third parameter not used 478 $shortproductkey =~ s/\s/\_/g; # changing empty space to underline 479 480 $oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n"; 481 push(@{$directorytableref}, $oneline); 482 } 483 484 $oneline = "TARGETDIR\t\tSourceDir\n"; 485 push(@{$directorytableref}, $oneline); 486 487 $oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n"; 488 push(@{$directorytableref}, $oneline); 489 490 $oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n"; 491 push(@{$directorytableref}, $oneline); 492 493 $oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n"; 494 push(@{$directorytableref}, $oneline); 495 496 $oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n"; 497 push(@{$directorytableref}, $oneline); 498 499 $oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n"; 500 push(@{$directorytableref}, $oneline); 501 502 $oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n"; 503 push(@{$directorytableref}, $oneline); 504 505 $oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n"; 506 push(@{$directorytableref}, $oneline); 507 508 $oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n"; 509 push(@{$directorytableref}, $oneline); 510 511 if ( $installer::globals::usesharepointpath ) 512 { 513 $oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n"; 514 push(@{$directorytableref}, $oneline); 515 } 516 517 $oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n"; 518 push(@{$directorytableref}, $oneline); 519 520 my $localtemplatefoldername = $installer::globals::templatefoldername; 521 my $directorytableentry = $localtemplatefoldername; 522 my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir"); 523 if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; } 524 $oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n"; 525 push(@{$directorytableref}, $oneline); 526 527 if ( $installer::globals::fontsdirname ) 528 { 529 $oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n"; 530 } 531 else 532 { 533 $oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n"; 534 } 535 536 push(@{$directorytableref}, $oneline); 537 538} 539 540############################################### 541# Creating the file Director.idt dynamically 542############################################### 543 544sub create_directory_table ($$$$) 545{ 546 my ($directoryref, $basedir, $allvariableshashref, $loggingdir) = @_; 547 548 # Structure of the directory table: 549 # Directory Directory_Parent DefaultDir 550 # Directory is a unique identifier 551 # Directory_Parent is the unique identifier of the parent 552 # DefaultDir is .:APPLIC~1|Application Data with 553 # Before ":" : [sourcedir]:[destdir] (not programmed yet) 554 # After ":" : 8+3 and not 8+3 the destination directory name 555 556 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table start"); 557 558 my @directorytable = (); 559 my $infoline; 560 561 overwrite_programfilesfolder($allvariableshashref); 562 create_unique_directorynames($directoryref, $allvariableshashref); 563 create_defaultdir_directorynames($directoryref); # only destdir! 564 set_installlocation_directory($directoryref, $allvariableshashref); 565 installer::windows::idtglobal::write_idt_header(\@directorytable, "directory"); 566 add_root_directories(\@directorytable, $allvariableshashref); 567 create_directorytable_from_collection(\@directorytable, $directoryref); 568 569 # Saving the file 570 571 my $directorytablename = $basedir . $installer::globals::separator . "Director.idt"; 572 installer::files::save_file($directorytablename ,\@directorytable); 573 $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename); 574 575 $installer::logger::Lang->add_timestamp("Performance Info: Directory Table end"); 576} 577 5781; 579