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::file; 25 26use Digest::MD5; 27use installer::existence; 28use installer::exiter; 29use installer::files; 30use installer::globals; 31use installer::logger; 32use installer::pathanalyzer; 33use installer::worker; 34use installer::windows::font; 35use installer::windows::idtglobal; 36use installer::windows::msiglobal; 37use installer::windows::language; 38 39########################################################################## 40# Assigning one cabinet file to each file. This is requrired, 41# if cabinet files shall be equivalent to packages. 42########################################################################## 43 44sub assign_cab_to_files 45{ 46 my ( $filesref ) = @_; 47 48 my $infoline = ""; 49 50 foreach my $file (@$filesref) 51 { 52 if ( ! exists($file->{'modules'}) ) 53 { 54 installer::exiter::exit_program( 55 sprintf("ERROR: No module assignment found for %s", $file->{'gid'}), 56 "assign_cab_to_files"); 57 } 58 my $module = $file->{'modules'}; 59 # If modules contains a list of modules, only taking the first one. 60 if ( $module =~ /^\s*(.*?)\,/ ) { $module = $1; } 61 62 if ( ! exists($installer::globals::allcabinetassigns{$module}) ) 63 { 64 installer::exiter::exit_program( 65 sprintf("ERROR: No cabinet file assigned to module \"%s\" %s", 66 $module, 67 $file->{'gid'}), 68 "assign_cab_to_files"); 69 } 70 $file->{'assignedcabinetfile'} = $installer::globals::allcabinetassigns{$module}; 71 72 # Counting the files in each cabinet file 73 if ( ! exists($installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}}) ) 74 { 75 $installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}} = 1; 76 } 77 else 78 { 79 $installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}}++; 80 } 81 } 82 83 # assigning startsequencenumbers for each cab file 84 85 my %count = (); 86 my $offset = 1; 87 foreach my $cabfile ( sort keys %installer::globals::cabfilecounter ) 88 { 89 my $filecount = $installer::globals::cabfilecounter{$cabfile}; 90 $count{$cabfile} = $filecount; 91 $installer::globals::cabfilecounter{$cabfile} = $offset; 92 $offset = $offset + $filecount; 93 94 $installer::globals::lastsequence{$cabfile} = $offset - 1; 95 } 96 97 # logging the number of files in each cabinet file 98 99 $installer::logger::Lang->print("\n"); 100 $installer::logger::Lang->print("Cabinet files:\n"); 101 foreach my $cabfile (sort keys %installer::globals::cabfilecounter) 102 { 103 $installer::logger::Lang->printf( 104 "%-30s : %4s files, from %4d to %4d\n", 105 $cabfile, 106 $count{$cabfile}, 107 $installer::globals::cabfilecounter{$cabfile}, 108 $installer::globals::lastsequence{$cabfile}); 109 } 110} 111 112########################################################################## 113# Assigning sequencenumbers to files. This is requrired, 114# if cabinet files shall be equivalent to packages. 115########################################################################## 116 117sub assign_sequencenumbers_to_files 118{ 119 my ( $filesref ) = @_; 120 121 my %directaccess = (); 122 my %allassigns = (); 123 124 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 125 { 126 my $onefile = ${$filesref}[$i]; 127 128 # Keeping order in cabinet files 129 # -> collecting all files in one cabinet file 130 # -> sorting files and assigning numbers 131 132 # Saving counter $i for direct access into files array 133 # "destination" of the file is a unique identifier ('Name' is not unique!) 134 if ( exists($directaccess{$onefile->{'destination'}}) ) { installer::exiter::exit_program("ERROR: 'destination' at file not unique: $onefile->{'destination'}", "assign_sequencenumbers_to_files"); } 135 $directaccess{$onefile->{'destination'}} = $i; 136 137 my $cabfilename = $onefile->{'assignedcabinetfile'}; 138 # collecting files in cabinet files 139 if ( ! exists($allassigns{$cabfilename}) ) 140 { 141 my %onecabfile = (); 142 $onecabfile{$onefile->{'destination'}} = 1; 143 $allassigns{$cabfilename} = \%onecabfile; 144 } 145 else 146 { 147 $allassigns{$cabfilename}->{$onefile->{'destination'}} = 1; 148 } 149 } 150 151 # Sorting each hash and assigning numbers 152 # The destination of the file determines the sort order, not the filename! 153 my $cabfile; 154 foreach $cabfile ( sort keys %allassigns ) 155 { 156 my $counter = $installer::globals::cabfilecounter{$cabfile}; 157 my $dest; 158 foreach $dest ( sort keys %{$allassigns{$cabfile}} ) # <- sorting the destination! 159 { 160 my $directaccessnumber = $directaccess{$dest}; 161 ${$filesref}[$directaccessnumber]->{'assignedsequencenumber'} = $counter; 162 $counter++; 163 } 164 } 165} 166 167######################################################### 168# Create a shorter version of a long component name, 169# because maximum length in msi database is 72. 170# Attention: In multi msi installation sets, the short 171# names have to be unique over all packages, because 172# this string is used to create the globally unique id 173# -> no resetting of 174# %installer::globals::allshortcomponents 175# after a package was created. 176# Using no counter because of reproducibility. 177######################################################### 178 179sub generate_new_short_componentname 180{ 181 my ($componentname) = @_; 182 183 my $startversion = substr($componentname, 0, 60); # taking only the first 60 characters 184 my $subid = installer::windows::msiglobal::calculate_id($componentname, 9); # taking only the first 9 digits 185 my $shortcomponentname = $startversion . "_" . $subid; 186 187 if ( exists($installer::globals::allshortcomponents{$shortcomponentname}) ) { installer::exiter::exit_program("Failed to create unique component name: \"$shortcomponentname\"", "generate_new_short_componentname"); } 188 189 $installer::globals::allshortcomponents{$shortcomponentname} = 1; 190 191 return $shortcomponentname; 192} 193 194############################################### 195# Generating the component name from a file 196############################################### 197 198sub get_file_component_name 199{ 200 my ($fileref, $filesref) = @_; 201 202 my $componentname = ""; 203 204 # Special handling for files with ASSIGNCOMPOMENT 205 206 my $styles = ""; 207 if ( $fileref->{'Styles'} ) { $styles = $fileref->{'Styles'}; } 208 if ( $styles =~ /\bASSIGNCOMPOMENT\b/ ) 209 { 210 $componentname = get_component_from_assigned_file($fileref->{'AssignComponent'}, $filesref); 211 } 212 else 213 { 214 # In this function exists the rule to create components from files 215 # Rule: 216 # Two files get the same componentid, if: 217 # both have the same destination directory. 218 # both have the same "gid" -> both were packed in the same zip file 219 # All other files are included into different components! 220 221 # my $componentname = $fileref->{'gid'} . "_" . $fileref->{'Dir'}; 222 223 # $fileref->{'Dir'} is not sufficient! All files in a zip file have the same $fileref->{'Dir'}, 224 # but can be in different subdirectories. 225 # Solution: destination=share\Scripts\beanshell\Capitalise\capitalise.bsh 226 # in which the filename (capitalise.bsh) has to be removed and all backslashes (slashes) are 227 # converted into underline. 228 229 my $destination = $fileref->{'destination'}; 230 installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination); 231 $destination =~ s/\s//g; 232 $destination =~ s/\\/\_/g; 233 $destination =~ s/\//\_/g; 234 $destination =~ s/\_\s*$//g; # removing ending underline 235 236 $componentname = $fileref->{'gid'} . "__" . $destination; 237 238 # Files with different languages, need to be packed into different components. 239 # Then the installation of the language specific component is determined by a language condition. 240 241 if ( $fileref->{'ismultilingual'} ) 242 { 243 my $officelanguage = $fileref->{'specificlanguage'}; 244 $componentname = $componentname . "_" . $officelanguage; 245 } 246 247 $componentname = lc($componentname); # componentnames always lowercase 248 249 $componentname =~ s/\-/\_/g; # converting "-" to "_" 250 $componentname =~ s/\./\_/g; # converting "-" to "_" 251 252 # Attention: Maximum length for the componentname is 72 253 # %installer::globals::allcomponents_in_this_database : resetted for each database 254 # %installer::globals::allcomponents : not resetted for each database 255 # Component strings must be unique for the complete product, because they are used for 256 # the creation of the globally unique identifier. 257 258 my $fullname = $componentname; # This can be longer than 72 259 260 if (( exists($installer::globals::allcomponents{$fullname}) ) && ( ! exists($installer::globals::allcomponents_in_this_database{$fullname}) )) 261 { 262 # This is not allowed: One component cannot be installed with different packages. 263 installer::exiter::exit_program("ERROR: Component \"$fullname\" is already included into another package. This is not allowed.", "get_file_component_name"); 264 } 265 266 if ( exists($installer::globals::allcomponents{$fullname}) ) 267 { 268 $componentname = $installer::globals::allcomponents{$fullname}; 269 } 270 else 271 { 272 if ( length($componentname) > 70 ) 273 { 274 $componentname = generate_new_short_componentname($componentname); # This has to be unique for the complete product, not only one package 275 } 276 277 $installer::globals::allcomponents{$fullname} = $componentname; 278 $installer::globals::allcomponents_in_this_database{$fullname} = 1; 279 } 280 281 # $componentname =~ s/gid_file_/g_f_/g; 282 # $componentname =~ s/_extra_/_e_/g; 283 # $componentname =~ s/_config_/_c_/g; 284 # $componentname =~ s/_org_openoffice_/_o_o_/g; 285 # $componentname =~ s/_program_/_p_/g; 286 # $componentname =~ s/_typedetection_/_td_/g; 287 # $componentname =~ s/_linguistic_/_l_/g; 288 # $componentname =~ s/_module_/_m_/g; 289 # $componentname =~ s/_optional_/_opt_/g; 290 # $componentname =~ s/_packages/_pack/g; 291 # $componentname =~ s/_menubar/_mb/g; 292 # $componentname =~ s/_common_/_cm_/g; 293 # $componentname =~ s/_export_/_exp_/g; 294 # $componentname =~ s/_table_/_tb_/g; 295 # $componentname =~ s/_sofficecfg_/_sc_/g; 296 # $componentname =~ s/_soffice_cfg_/_sc_/g; 297 # $componentname =~ s/_startmodulecommands_/_smc_/g; 298 # $componentname =~ s/_drawimpresscommands_/_dic_/g; 299 # $componentname =~ s/_basiccommands_/_bac_/g; 300 # $componentname =~ s/_basicidecommands_/_baic_/g; 301 # $componentname =~ s/_genericcommands_/_genc_/g; 302 # $componentname =~ s/_bibliographycommands_/_bibc_/g; 303 # $componentname =~ s/_gentiumbookbasicbolditalic_/_gbbbi_/g; 304 # $componentname =~ s/_share_/_s_/g; 305 # $componentname =~ s/_extension_/_ext_/g; 306 # $componentname =~ s/_extensions_/_exs_/g; 307 # $componentname =~ s/_modules_/_ms_/g; 308 # $componentname =~ s/_uiconfig_zip_/_ucz_/g; 309 # $componentname =~ s/_productivity_/_pr_/g; 310 # $componentname =~ s/_wizard_/_wz_/g; 311 # $componentname =~ s/_import_/_im_/g; 312 # $componentname =~ s/_javascript_/_js_/g; 313 # $componentname =~ s/_template_/_tpl_/g; 314 # $componentname =~ s/_tplwizletter_/_twl_/g; 315 # $componentname =~ s/_beanshell_/_bs_/g; 316 # $componentname =~ s/_presentation_/_bs_/g; 317 # $componentname =~ s/_columns_/_cls_/g; 318 # $componentname =~ s/_python_/_py_/g; 319 320 # $componentname =~ s/_tools/_ts/g; 321 # $componentname =~ s/_transitions/_trs/g; 322 # $componentname =~ s/_scriptbinding/_scrb/g; 323 # $componentname =~ s/_spreadsheet/_ssh/g; 324 # $componentname =~ s/_publisher/_pub/g; 325 # $componentname =~ s/_presenter/_pre/g; 326 # $componentname =~ s/_registry/_reg/g; 327 328 # $componentname =~ s/screen/sc/g; 329 # $componentname =~ s/wordml/wm/g; 330 # $componentname =~ s/openoffice/oo/g; 331 } 332 333 return $componentname; 334} 335 336#################################################################### 337# Returning the component name for a defined file gid. 338# This is necessary for files with flag ASSIGNCOMPOMENT 339#################################################################### 340 341sub get_component_from_assigned_file 342{ 343 my ($gid, $filesref) = @_; 344 345 my $onefile = installer::existence::get_specified_file($filesref, $gid); 346 my $componentname = ""; 347 if ( $onefile->{'componentname'} ) { $componentname = $onefile->{'componentname'}; } 348 else { installer::exiter::exit_program("ERROR: No component defined for file: $gid", "get_component_from_assigned_file"); } 349 350 return $componentname; 351} 352 353#################################################################### 354# Generating the special filename for the database file File.idt 355# Sample: CONTEXTS, CONTEXTS1 356# This name has to be unique. 357# In most cases this is simply the filename. 358#################################################################### 359 360sub generate_unique_filename_for_filetable ($$) 361{ 362 my ($fileref, $component) = @_; 363 364 # This new filename has to be saved into $fileref, because this is needed to find the source. 365 # The filename sbasic.idx/OFFSETS is changed to OFFSETS, but OFFSETS is not unique. 366 # In this procedure names like OFFSETS5 are produced. And exactly this string has to be added to 367 # the array of all files. 368 369 my $uniquefilename = ""; 370 my $counter = 0; 371 372 if ( $fileref->{'Name'} ) { $uniquefilename = $fileref->{'Name'}; } 373 # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs 374 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$uniquefilename); 375 376 $uniquefilename =~ s/\-/\_/g; # no "-" allowed 377 $uniquefilename =~ s/\@/\_/g; # no "@" allowed 378 $uniquefilename =~ s/\$/\_/g; # no "$" allowed 379 $uniquefilename =~ s/^\s*\./\_/g; # no "." at the beginning allowed allowed 380 $uniquefilename =~ s/^\s*\d/\_d/g; # no number at the beginning allowed allowed (even file "0.gif", replacing to "_d.gif") 381 $uniquefilename =~ s/org_openoffice_/ooo_/g; # shorten the unique file name 382 383 my $lcuniquefilename = lc($uniquefilename); # only lowercase names 384 385 my $newname = 0; 386 387 if ( ! exists($installer::globals::alllcuniquefilenames{$lcuniquefilename})) 388 { 389 $installer::globals::alluniquefilenames{$uniquefilename} = 1; 390 $installer::globals::alllcuniquefilenames{$lcuniquefilename} = 1; 391 $newname = 1; 392 } 393 394 if ( ! $newname ) 395 { 396 # adding a number until the name is really unique: OFFSETS, OFFSETS1, OFFSETS2, ... 397 # But attention: Making "abc.xcu" to "abc1.xcu" 398 399 my $uniquefilenamebase = $uniquefilename; 400 401 do 402 { 403 $counter++; 404 405 if ( $uniquefilenamebase =~ /\./ ) 406 { 407 $uniquefilename = $uniquefilenamebase; 408 $uniquefilename =~ s/\./$counter\./; 409 } 410 else 411 { 412 $uniquefilename = $uniquefilenamebase . $counter; 413 } 414 415 $newname = 0; 416 $lcuniquefilename = lc($uniquefilename); # only lowercase names 417 418 if ( ! exists($installer::globals::alllcuniquefilenames{$lcuniquefilename})) 419 { 420 $installer::globals::alluniquefilenames{$uniquefilename} = 1; 421 $installer::globals::alllcuniquefilenames{$lcuniquefilename} = 1; 422 $newname = 1; 423 } 424 } 425 until ( $newname ) 426 } 427 428 return $uniquefilename; 429} 430 431#################################################################### 432# Generating the special file column for the database file File.idt 433# Sample: NAMETR~1.TAB|.nametranslation.table 434# The first part has to be 8.3 conform. 435#################################################################### 436 437sub generate_filename_for_filetable ($$) 438{ 439 my ($fileref, $shortnamesref) = @_; 440 441 my $returnstring = ""; 442 443 my $filename = $fileref->{'Name'}; 444 445 # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs 446 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$filename); 447 448 my $shortstring = installer::windows::idtglobal::make_eight_three_conform_with_hash($filename, "file", $shortnamesref); 449 450 if ( $shortstring eq $filename ) 451 { 452 # nothing changed 453 $returnstring = $filename; 454 } 455 else 456 { 457 $returnstring = $shortstring . "\|" . $filename; 458 } 459 460 return $returnstring; 461} 462 463######################################### 464# Returning the filesize of a file 465######################################### 466 467sub get_filesize 468{ 469 my ($fileref) = @_; 470 471 my $file = $fileref->{'sourcepath'}; 472 473 my $filesize; 474 475 if ( -f $file ) # test of existence. For instance services.rdb does not always exist 476 { 477 $filesize = ( -s $file ); # file size can be "0" 478 } 479 else 480 { 481 $filesize = -1; 482 } 483 484 return $filesize; 485} 486 487############################################# 488# Returning the file version, if required 489# Sample: "8.0.1.8976"; 490############################################# 491 492sub get_fileversion 493{ 494 my ($onefile, $allvariables, $styles) = @_; 495 496 my $fileversion = ""; 497 498 if ( $allvariables->{'USE_FILEVERSION'} ) 499 { 500 if ( ! $allvariables->{'LIBRARYVERSION'} ) 501 { 502 installer::exiter::exit_program("ERROR: USE_FILEVERSION is set, but not LIBRARYVERSION", "get_fileversion"); 503 } 504 my $libraryversion = $allvariables->{'LIBRARYVERSION'}; 505 if ( $libraryversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) 506 { 507 my $major = $1; 508 my $minor = $2; 509 my $micro = $3; 510 my $concat = 100 * $minor + $micro; 511 $libraryversion = $major . "\." . $concat; 512 } 513 my $vendornumber = 0; 514 if ( $allvariables->{'VENDORPATCHVERSION'} ) 515 { 516 $vendornumber = $allvariables->{'VENDORPATCHVERSION'}; 517 } 518 $fileversion = $libraryversion . "\." . $installer::globals::buildid . "\." . $vendornumber; 519 if ( $onefile->{'FileVersion'} ) 520 { 521 # overriding FileVersion in scp 522 $fileversion = $onefile->{'FileVersion'}; 523 } 524 } 525 526 if ( $installer::globals::prepare_winpatch ) 527 { 528 # Windows patches do not allow this version # -> who says so? 529 $fileversion = ""; 530 } 531 532 return $fileversion; 533} 534 535############################################# 536# Returning the Windows language of a file 537############################################# 538 539sub get_language_for_file 540{ 541 my ($fileref) = @_; 542 543 my $language = ""; 544 545 if ( $fileref->{'specificlanguage'} ) { $language = $fileref->{'specificlanguage'}; } 546 547 if ( $language eq "" ) 548 { 549 $language = 0; # language independent 550 # If this is not a font, the return value should be "0" (Check ICE 60) 551 my $styles = ""; 552 if ( $fileref->{'Styles'} ) { $styles = $fileref->{'Styles'}; } 553 if ( $styles =~ /\bFONT\b/ ) { $language = ""; } 554 } 555 else 556 { 557 $language = installer::windows::language::get_windows_language($language); 558 } 559 560 return $language; 561} 562 563#################################################################### 564# Creating a new KeyPath for components in TemplatesFolder. 565#################################################################### 566 567sub generate_registry_keypath 568{ 569 my ($onefile) = @_; 570 571 my $keypath = $onefile->{'Name'}; 572 $keypath =~ s/\.//g; 573 $keypath = lc($keypath); 574 $keypath = "userreg_" . $keypath; 575 576 return $keypath; 577} 578 579################################################################### 580# Collecting further conditions for the component table. 581# This is used by multilayer products, to enable installation 582# of separate layers. 583################################################################### 584 585sub get_tree_condition_for_component 586{ 587 my ($onefile, $componentname) = @_; 588 589 if ( $onefile->{'destination'} ) 590 { 591 my $dest = $onefile->{'destination'}; 592 593 # Comparing the destination path with 594 # $installer::globals::hostnametreestyles{$hostname} = $treestyle; 595 # (-> hostname is the key, the style the value!) 596 597 foreach my $hostname ( keys %installer::globals::hostnametreestyles ) 598 { 599 if (( $dest eq $hostname ) || ( $dest =~ /^\s*\Q$hostname\E\\/ )) 600 { 601 # the value is the style 602 my $style = $installer::globals::hostnametreestyles{$hostname}; 603 # the condition is saved in %installer::globals::treestyles 604 my $condition = $installer::globals::treestyles{$style}; 605 # Saving condition to be added in table Property 606 $installer::globals::usedtreeconditions{$condition} = 1; 607 $condition = $condition . "=1"; 608 # saving this condition 609 $installer::globals::treeconditions{$componentname} = $condition; 610 611 # saving also at the file, for usage in fileinfo 612 $onefile->{'layer'} = $installer::globals::treelayername{$style}; 613 } 614 } 615 } 616} 617 618############################################ 619# Collecting all short names, that are 620# already used by the old database 621############################################ 622 623sub collect_shortnames_from_old_database 624{ 625 my ($uniquefilenamehashref, $shortnameshashref) = @_; 626 627 foreach my $key ( keys %{$uniquefilenamehashref} ) 628 { 629 my $value = $uniquefilenamehashref->{$key}; # syntax of $value: ($uniquename;$shortname) 630 631 if ( $value =~ /^\s*(.*?)\;\s*(.*?)\s*$/ ) 632 { 633 my $shortstring = $2; 634 $shortnameshashref->{$shortstring} = 1; # adding the shortname to the array of all shortnames 635 } 636 } 637} 638 639############################################ 640# Creating the file File.idt dynamically 641############################################ 642 643sub create_files_table ($$$$) 644{ 645 my ($filesref, $allfilecomponentsref, $basedir, $allvariables) = @_; 646 647 $installer::logger::Lang->add_timestamp("Performance Info: File Table start"); 648 649 # Structure of the files table: 650 # File Component_ FileName FileSize Version Language Attributes Sequence 651 # In this function, all components are created. 652 # 653 # $allfilecomponentsref is empty at the beginning 654 655 my $infoline; 656 657 my @allfiles = (); 658 my @filetable = (); 659 my @filehashtable = (); 660 my %allfilecomponents = (); 661 my $counter = 0; 662 663 if ( $^O =~ /cygwin/i ) { installer::worker::generate_cygwin_pathes($filesref); } 664 665 # The filenames must be collected because of uniqueness 666 # 01-44-~1.DAT, 01-44-~2.DAT, ... 667 # my @shortnames = (); 668 my %shortnames = (); 669 670 installer::windows::idtglobal::write_idt_header(\@filetable, "file"); 671 installer::windows::idtglobal::write_idt_header(\@filehashtable, "filehash"); 672 673 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 674 { 675 my %file = (); 676 677 my $onefile = ${$filesref}[$i]; 678 679 my $styles = ""; 680 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } 681 if (( $styles =~ /\bJAVAFILE\b/ ) && ( ! ($allvariables->{'JAVAPRODUCT'} ))) { next; } 682 683 $file{'Component_'} = get_file_component_name($onefile, $filesref); 684 $file{'File'} = generate_unique_filename_for_filetable($onefile, $file{'Component_'}); 685 686 $onefile->{'uniquename'} = $file{'File'}; 687 $onefile->{'componentname'} = $file{'Component_'}; 688 689 # Collecting all components 690 # if (!(installer::existence::exists_in_array($file{'Component_'}, $allfilecomponentsref))) { push(@{$allfilecomponentsref}, $file{'Component_'}); } 691 692 if ( ! exists($allfilecomponents{$file{'Component_'}}) ) { $allfilecomponents{$file{'Component_'}} = 1; } 693 694 $file{'FileName'} = generate_filename_for_filetable($onefile, \%shortnames); 695 696 $file{'FileSize'} = get_filesize($onefile); 697 698 $file{'Version'} = get_fileversion($onefile, $allvariables, $styles); 699 700 $file{'Language'} = get_language_for_file($onefile); 701 702 if ( $styles =~ /\bDONT_PACK\b/ ) { $file{'Attributes'} = "8192"; } 703 else { $file{'Attributes'} = "16384"; } 704 705 # $file{'Attributes'} = "16384"; # Sourcefile is packed 706 # $file{'Attributes'} = "8192"; # Sourcefile is unpacked 707 708 $installer::globals::insert_file_at_end = 0; 709 $counter++; 710 $file{'Sequence'} = $counter; 711 712 $onefile->{'sequencenumber'} = $file{'Sequence'}; 713 714 my $oneline = $file{'File'} . "\t" . $file{'Component_'} . "\t" . $file{'FileName'} . "\t" 715 . $file{'FileSize'} . "\t" . $file{'Version'} . "\t" . $file{'Language'} . "\t" 716 . $file{'Attributes'} . "\t" . $file{'Sequence'} . "\n"; 717 718 push(@filetable, $oneline); 719 720 if ( ! $installer::globals::insert_file_at_end ) { push(@allfiles, $onefile); } 721 722 # Collecting all component conditions 723 if ( $onefile->{'ComponentCondition'} ) 724 { 725 if ( ! exists($installer::globals::componentcondition{$file{'Component_'}})) 726 { 727 $installer::globals::componentcondition{$file{'Component_'}} = $onefile->{'ComponentCondition'}; 728 } 729 } 730 731 # Collecting also all tree conditions for multilayer products 732 get_tree_condition_for_component($onefile, $file{'Component_'}); 733 734 # Collecting all component names, that have flag VERSION_INDEPENDENT_COMP_ID 735 # This should be all components with constant API, for example URE 736 if ( $styles =~ /\bVERSION_INDEPENDENT_COMP_ID\b/ ) 737 { 738 $installer::globals::base_independent_components{$onefile->{'componentname'}} = 1; 739 } 740 741 # Collecting all component ids, that are defined at files in scp project (should not be used anymore) 742 if ( $onefile->{'CompID'} ) 743 { 744 if ( ! exists($installer::globals::componentid{$onefile->{'componentname'}})) 745 { 746 $installer::globals::componentid{$onefile->{'componentname'}} = $onefile->{'CompID'}; 747 } 748 else 749 { 750 if ( $installer::globals::componentid{$onefile->{'componentname'}} ne $onefile->{'CompID'} ) 751 { 752 installer::exiter::exit_program("ERROR: There is already a ComponentID for component \"$onefile->{'componentname'}\" : \"$installer::globals::componentid{$onefile->{'componentname'}}\" . File \"$onefile->{'gid'}\" uses \"$onefile->{'CompID'}\" !", "create_files_table"); 753 } 754 } 755 756 # Also checking vice versa. Is this ComponentID already used? If yes, is the componentname the same? 757 758 if ( ! exists($installer::globals::comparecomponentname{$onefile->{'CompID'}})) 759 { 760 $installer::globals::comparecomponentname{$onefile->{'CompID'}} = $onefile->{'componentname'}; 761 } 762 else 763 { 764 if ( $installer::globals::comparecomponentname{$onefile->{'CompID'}} ne $onefile->{'componentname'} ) 765 { 766 installer::exiter::exit_program("ERROR: There is already a component for ComponentID \"$onefile->{'CompID'}\" : \"$installer::globals::comparecomponentname{$onefile->{'CompID'}}\" . File \"$onefile->{'gid'}\" has same component id but is included in component \"$onefile->{'componentname'}\" !", "create_files_table"); 767 } 768 } 769 } 770 771 # Collecting all language specific conditions 772 # if ( $onefile->{'haslanguagemodule'} ) 773 if ( $onefile->{'ismultilingual'} ) 774 { 775 if ( $onefile->{'ComponentCondition'} ) { installer::exiter::exit_program("ERROR: Cannot set language condition. There is already another component condition for file $onefile->{'gid'}: \"$onefile->{'ComponentCondition'}\" !", "create_files_table"); } 776 777 if ( $onefile->{'specificlanguage'} eq "" ) { installer::exiter::exit_program("ERROR: There is no specific language for file at language module: $onefile->{'gid'} !", "create_files_table"); } 778 my $locallanguage = $onefile->{'specificlanguage'}; 779 my $property = "IS" . $file{'Language'}; 780 my $value = 1; 781 my $condition = $property . "=" . $value; 782 783 $onefile->{'ComponentCondition'} = $condition; 784 785 if ( exists($installer::globals::componentcondition{$file{'Component_'}})) 786 { 787 if ( $installer::globals::componentcondition{$file{'Component_'}} ne $condition ) { installer::exiter::exit_program("ERROR: There is already another component condition for file $onefile->{'gid'}: \"$installer::globals::componentcondition{$file{'Component_'}}\" and \"$condition\" !", "create_files_table"); } 788 } 789 else 790 { 791 $installer::globals::componentcondition{$file{'Component_'}} = $condition; 792 } 793 794 # collecting all properties for table Property 795 if ( ! exists($installer::globals::languageproperties{$property}) ) { $installer::globals::languageproperties{$property} = $value; } 796 } 797 798 if ( $installer::globals::prepare_winpatch ) 799 { 800 my $path = $onefile->{'sourcepath'}; 801 if ( $^O =~ /cygwin/i ) { $path = $onefile->{'cyg_sourcepath'}; } 802 803 open(FILE, $path) or die "ERROR: Can't open $path for creating file hash"; 804 binmode(FILE); 805 my $hashinfo = pack("l", 20); 806 $hashinfo .= Digest::MD5->new->addfile(*FILE)->digest; 807 808 my @i = unpack ('x[l]l4', $hashinfo); 809 $oneline = $file{'File'} . "\t" . 810 "0" . "\t" . 811 $i[0] . "\t" . 812 $i[1] . "\t" . 813 $i[2] . "\t" . 814 $i[3] . "\n"; 815 push (@filehashtable, $oneline); 816 } 817 818 # Saving the sequence number in a hash with uniquefilename as key. 819 # This is used for better performance in "save_packorder" 820 $installer::globals::uniquefilenamesequence{$onefile->{'uniquename'}} = $onefile->{'sequencenumber'}; 821 822 # Special handling for files in PREDEFINED_OSSHELLNEWDIR. These components 823 # need as KeyPath a RegistryItem in HKCU 824 my $destdir = ""; 825 if ( $onefile->{'Dir'} ) { $destdir = $onefile->{'Dir'}; } 826 827 if (( $destdir =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ ) || ( $onefile->{'needs_user_registry_key'} )) 828 { 829 my $keypath = generate_registry_keypath($onefile); 830 $onefile->{'userregkeypath'} = $keypath; 831 push(@installer::globals::userregistrycollector, $onefile); 832 $installer::globals::addeduserregitrykeys = 1; 833 } 834 } 835 836 # putting content from %allfilecomponents to $allfilecomponentsref for later usage 837 foreach $localkey (keys %allfilecomponents ) { push( @{$allfilecomponentsref}, $localkey); } 838 839 my $filetablename = $basedir . $installer::globals::separator . "File.idt"; 840 installer::files::save_file($filetablename ,\@filetable); 841 $installer::logger::Lang->print("\n"); 842 $installer::logger::Lang->printf("Created idt file: %s\n", $filetablename); 843 844 $installer::logger::Lang->add_timestamp("Performance Info: File Table end"); 845 846 my $filehashtablename = $basedir . $installer::globals::separator . "MsiFileHash.idt"; 847 installer::files::save_file($filehashtablename ,\@filehashtable); 848 $installer::logger::Lang->print("\n"); 849 $installer::logger::Lang->printf("Created idt file: %s\n", $filehashtablename); 850 851 # Now the new files can be added to the files collector (only in update packaging processes) 852 if ( $installer::globals::newfilesexist ) 853 { 854 foreach my $seq (sort keys %installer::globals::newfilescollector) { push(@allfiles, $installer::globals::newfilescollector{$seq}) } 855 } 856 857 return \@allfiles; 858} 859 8601; 861