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::msiglobal; 25 26use Cwd; 27use Digest::MD5; 28use installer::converter; 29use installer::exiter; 30use installer::files; 31use installer::globals; 32use installer::logger; 33use installer::pathanalyzer; 34use installer::remover; 35use installer::scriptitems; 36use installer::systemactions; 37use installer::worker; 38use installer::windows::idtglobal; 39use installer::windows::language; 40 41########################################################################### 42# Generating the header of the ddf file. 43# The usage of ddf files is needed, because makecab.exe can only include 44# one sourcefile into a cab file 45########################################################################### 46 47sub write_ddf_file_header 48{ 49 my ($ddffileref, $cabinetfile, $installdir) = @_; 50 51 my $oneline; 52 53 $oneline = ".Set CabinetName1=" . $cabinetfile . "\n"; 54 push(@{$ddffileref} ,$oneline); 55 $oneline = ".Set ReservePerCabinetSize=128\n"; # This reserves space for a digital signature. 56 push(@{$ddffileref} ,$oneline); 57 $oneline = ".Set MaxDiskSize=2147483648\n"; # This allows the .cab file to get a size of 2 GB. 58 push(@{$ddffileref} ,$oneline); 59 $oneline = ".Set CompressionType=LZX\n"; 60 push(@{$ddffileref} ,$oneline); 61 $oneline = ".Set Compress=ON\n"; 62 push(@{$ddffileref} ,$oneline); 63 $oneline = ".Set CompressionLevel=$installer::globals::cabfilecompressionlevel\n"; 64 push(@{$ddffileref} ,$oneline); 65 $oneline = ".Set Cabinet=ON\n"; 66 push(@{$ddffileref} ,$oneline); 67 $oneline = ".Set DiskDirectoryTemplate=" . $installdir . "\n"; 68 push(@{$ddffileref} ,$oneline); 69} 70 71########################################################################## 72# Lines in ddf files must not contain more than 256 characters 73########################################################################## 74 75sub check_ddf_file 76{ 77 my ( $ddffile, $ddffilename ) = @_; 78 79 my $maxlength = 0; 80 my $maxline = 0; 81 my $linelength = 0; 82 my $linenumber = 0; 83 84 for ( my $i = 0; $i <= $#{$ddffile}; $i++ ) 85 { 86 my $oneline = ${$ddffile}[$i]; 87 88 $linelength = length($oneline); 89 $linenumber = $i + 1; 90 91 if ( $linelength > 256 ) 92 { 93 installer::exiter::exit_program("ERROR \"$ddffilename\" line $linenumber: Lines in ddf files must not contain more than 256 characters!", "check_ddf_file"); 94 } 95 96 if ( $linelength > $maxlength ) 97 { 98 $maxlength = $linelength; 99 $maxline = $linenumber; 100 } 101 } 102 103 my $infoline = "Check of ddf file \"$ddffilename\": Maximum length \"$maxlength\" in line \"$maxline\" (allowed line length: 256 characters)\n"; 104 $installer::logger::Lang->print($infoline); 105} 106 107########################################################################## 108# Lines in ddf files must not be longer than 256 characters. 109# Therefore it can be useful to use relative pathes. Then it is 110# necessary to change into temp directory before calling 111# makecab.exe. 112########################################################################## 113 114sub make_relative_ddf_path 115{ 116 my ( $sourcepath ) = @_; 117 118 my $windowstemppath = $installer::globals::temppath; 119 120 if ( $^O =~ /cygwin/i ) 121 { 122 $windowstemppath = $installer::globals::cyg_temppath; 123 } 124 125 $sourcepath =~ s/\Q$windowstemppath\E//; 126 $sourcepath =~ s/^\\//; 127 128 return $sourcepath; 129} 130 131########################################################################## 132# Returning the order of the sequences in the files array. 133########################################################################## 134 135sub get_sequenceorder 136{ 137 my ($filesref) = @_; 138 139 my %order = (); 140 141 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 142 { 143 my $onefile = ${$filesref}[$i]; 144 if ( ! $onefile->{'assignedsequencenumber'} ) { installer::exiter::exit_program("ERROR: No sequence number assigned to $onefile->{'gid'} ($onefile->{'uniquename'})!", "get_sequenceorder"); } 145 $order{$onefile->{'assignedsequencenumber'}} = $i; 146 } 147 148 return \%order; 149} 150 151########################################################################## 152# Generation the list, in which the source of the files is connected 153# with the cabinet destination file. Because more than one file needs 154# to be included into a cab file, this has to be done via ddf files. 155########################################################################## 156 157sub generate_cab_file_list 158{ 159 my ($filesref, $installdir, $ddfdir, $allvariables) = @_; 160 161 my @cabfilelist = (); 162 163 installer::logger::include_header_into_logfile("Generating ddf files"); 164 165 $installer::logger::Lang->add_timestamp("Performance Info: ddf file generation start"); 166 167 if ( $^O =~ /cygwin/i ) { installer::worker::generate_cygwin_pathes($filesref); } 168 169 if ( $installer::globals::fix_number_of_cab_files ) 170 { 171 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 172 { 173 my $onefile = ${$filesref}[$i]; 174 my $cabinetfile = $onefile->{'cabinet'}; 175 my $sourcepath = $onefile->{'sourcepath'}; 176 if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; } 177 my $uniquename = $onefile->{'uniquename'}; 178 179 my $styles = ""; 180 my $doinclude = 1; 181 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }; 182 if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; } 183 184 185 # to avoid lines with more than 256 characters, it can be useful to use relative pathes 186 if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); } 187 188 # all files with the same cabinetfile are directly behind each other in the files collector 189 190 my @ddffile = (); 191 192 write_ddf_file_header(\@ddffile, $cabinetfile, $installdir); 193 194 my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n"; 195 if ( $doinclude ) { push(@ddffile, $ddfline); } 196 197 my $nextfile = ${$filesref}[$i+1]; 198 my $nextcabinetfile = ""; 199 200 if ( $nextfile->{'cabinet'} ) { $nextcabinetfile = $nextfile->{'cabinet'}; } 201 202 while ( $nextcabinetfile eq $cabinetfile ) 203 { 204 $sourcepath = $nextfile->{'sourcepath'}; 205 if ( $^O =~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; } 206 # to avoid lines with more than 256 characters, it can be useful to use relative pathes 207 if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); } 208 $uniquename = $nextfile->{'uniquename'}; 209 my $localdoinclude = 1; 210 my $nextfilestyles = ""; 211 if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; } 212 if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; } 213 $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n"; 214 if ( $localdoinclude ) { push(@ddffile, $ddfline); } 215 $i++; # increasing the counter! 216 $nextfile = ${$filesref}[$i+1]; 217 if ( $nextfile ) { $nextcabinetfile = $nextfile->{'cabinet'}; } 218 else { $nextcabinetfile = "_lastfile_"; } 219 } 220 221 # creating the DDF file 222 223 my $ddffilename = $cabinetfile; 224 $ddffilename =~ s/.cab/.ddf/; 225 $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//; 226 $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename; 227 228 installer::files::save_file($ddffilename ,\@ddffile); 229 my $infoline = "Created ddf file: $ddffilename\n"; 230 $installer::logger::Lang->print($infoline); 231 232 # lines in ddf files must not be longer than 256 characters 233 check_ddf_file(\@ddffile, $ddffilename); 234 235 # Writing the makecab system call 236 237 my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n"; 238 239 push(@cabfilelist, $oneline); 240 241 # collecting all ddf files 242 push(@installer::globals::allddffiles, $ddffilename); 243 } 244 } 245 elsif ( $installer::globals::one_cab_file ) 246 { 247 my @ddffile = (); 248 249 my $cabinetfile = ""; 250 251 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 252 { 253 my $onefile = ${$filesref}[$i]; 254 $cabinetfile = $onefile->{'cabinet'}; 255 my $sourcepath = $onefile->{'sourcepath'}; 256 if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; } 257 my $uniquename = $onefile->{'uniquename'}; 258 259 # to avoid lines with more than 256 characters, it can be useful to use relative pathes 260 if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); } 261 262 if ( $i == 0 ) { write_ddf_file_header(\@ddffile, $cabinetfile, $installdir); } 263 264 my $styles = ""; 265 my $doinclude = 1; 266 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }; 267 if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; } 268 269 my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n"; 270 if ( $doinclude ) { push(@ddffile, $ddfline); } 271 } 272 273 # creating the DDF file 274 275 my $ddffilename = $cabinetfile; 276 $ddffilename =~ s/.cab/.ddf/; 277 $ddfdir =~ s/[\/\\]\s*$//; 278 $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename; 279 280 installer::files::save_file($ddffilename ,\@ddffile); 281 my $infoline = "Created ddf file: $ddffilename\n"; 282 $installer::logger::Lang->print($infoline); 283 284 # lines in ddf files must not be longer than 256 characters 285 check_ddf_file(\@ddffile, $ddffilename); 286 287 # Writing the makecab system call 288 289 my $oneline = "makecab.exe /F " . $ddffilename . "\n"; 290 291 push(@cabfilelist, $oneline); 292 293 # collecting all ddf files 294 push(@installer::globals::allddffiles, $ddffilename); 295 } 296 else 297 { 298 installer::exiter::exit_program("ERROR: No cab file specification in globals.pm !", "create_media_table"); 299 } 300 301 $installer::logger::Lang->add_timestamp("Performance Info: ddf file generation end"); 302 303 return \@cabfilelist; # contains all system calls for packaging process 304} 305 306######################################################################## 307# Returning the file sequence of a specified file. 308######################################################################## 309 310sub get_file_sequence 311{ 312 my ($filesref, $uniquefilename) = @_; 313 314 my $sequence = ""; 315 my $found_sequence = 0; 316 317 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 318 { 319 my $onefile = ${$filesref}[$i]; 320 my $uniquename = $onefile->{'uniquename'}; 321 322 if ( $uniquename eq $uniquefilename ) 323 { 324 $sequence = $onefile->{'sequencenumber'}; 325 $found_sequence = 1; 326 last; 327 } 328 } 329 330 if ( ! $found_sequence ) { installer::exiter::exit_program("ERROR: No sequence found for $uniquefilename !", "get_file_sequence"); } 331 332 return $sequence; 333} 334 335######################################################################## 336# For update and patch reasons the pack order needs to be saved. 337# The pack order is saved in the ddf files; the names and locations 338# of the ddf files are saved in @installer::globals::allddffiles. 339# The outputfile "packorder.txt" can be saved in 340# $installer::globals::infodirectory . 341######################################################################## 342 343sub save_packorder 344{ 345 installer::logger::include_header_into_logfile("Saving pack order"); 346 347 $installer::logger::Lang->add_timestamp("Performance Info: saving pack order start"); 348 349 my $packorderfilename = "packorder.txt"; 350 $packorderfilename = $installer::globals::infodirectory . $installer::globals::separator . $packorderfilename; 351 352 my @packorder = (); 353 354 my $headerline = "\# Syntax\: Filetable_Sequence Cabinetfilename Physical_FileName Unique_FileName\n\n"; 355 push(@packorder, $headerline); 356 357 for ( my $i = 0; $i <= $#installer::globals::allddffiles; $i++ ) 358 { 359 my $ddffilename = $installer::globals::allddffiles[$i]; 360 my $ddffile = installer::files::read_file($ddffilename); 361 my $cabinetfile = ""; 362 363 for ( my $j = 0; $j <= $#{$ddffile}; $j++ ) 364 { 365 my $oneline = ${$ddffile}[$j]; 366 367 # Getting the Cabinet file name 368 369 if ( $oneline =~ /^\s*\.Set\s+CabinetName.*\=(.*?)\s*$/ ) { $cabinetfile = $1; } 370 if ( $oneline =~ /^\s*\.Set\s+/ ) { next; } 371 372 if ( $oneline =~ /^\s*\"(.*?)\"\s+(.*?)\s*$/ ) 373 { 374 my $sourcefile = $1; 375 my $uniquefilename = $2; 376 377 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$sourcefile); 378 379 # Using the hash created in create_files_table for performance reasons to get the sequence number 380 my $filesequence = ""; 381 if ( exists($installer::globals::uniquefilenamesequence{$uniquefilename}) ) { $filesequence = $installer::globals::uniquefilenamesequence{$uniquefilename}; } 382 else { installer::exiter::exit_program("ERROR: No sequence number value for $uniquefilename !", "save_packorder"); } 383 384 my $line = $filesequence . "\t" . $cabinetfile . "\t" . $sourcefile . "\t" . $uniquefilename . "\n"; 385 push(@packorder, $line); 386 } 387 } 388 } 389 390 installer::files::save_file($packorderfilename ,\@packorder); 391 392 $installer::logger::Lang->add_timestamp("Performance Info: saving pack order end"); 393} 394 395################################################################# 396# Returning the name of the msi database 397################################################################# 398 399sub get_msidatabasename 400{ 401 my ($allvariableshashref, $language) = @_; 402 403 my $databasename = $allvariableshashref->{'PRODUCTNAME'} . $allvariableshashref->{'PRODUCTVERSION'}; 404 $databasename = lc($databasename); 405 $databasename =~ s/\.//g; 406 $databasename =~ s/\-//g; 407 $databasename =~ s/\s//g; 408 409 # possibility to overwrite the name with variable DATABASENAME 410 if ( $allvariableshashref->{'DATABASENAME'} ) 411 { 412 $databasename = $allvariableshashref->{'DATABASENAME'}; 413 } 414 415 if ( $language ) 416 { 417 if (!($language eq "")) 418 { 419 $databasename .= "_$language"; 420 } 421 } 422 423 $databasename .= ".msi"; 424 425 return $databasename; 426} 427 428################################################################# 429# Creating the msi database 430# This works only on Windows 431################################################################# 432 433sub create_msi_database 434{ 435 my ($idtdirbase ,$msifilename) = @_; 436 437 # -f : path containing the idt files 438 # -d : msi database, including path 439 # -c : create database 440 # -i : include the following tables ("*" includes all available tables) 441 442 my $msidb = "msidb.exe"; # Has to be in the path 443 my $extraslash = ""; # Has to be set for non-ActiveState perl 444 445 installer::logger::include_header_into_logfile("Creating msi database"); 446 447 $idtdirbase = installer::converter::make_path_conform($idtdirbase); 448 449 $msifilename = installer::converter::make_path_conform($msifilename); 450 451 if ( $^O =~ /cygwin/i ) { 452 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 453 $idtdirbase =~ s/\//\\\\/g; 454 $msifilename =~ s/\//\\\\/g; 455 $extraslash = "\\"; 456 } 457 my $systemcall = $msidb . " -f " . $idtdirbase . " -d " . $msifilename . " -c " . "-i " . $extraslash . "*"; 458 459 my $returnvalue = system($systemcall); 460 461 my $infoline = "Systemcall: $systemcall\n"; 462 $installer::logger::Lang->print($infoline); 463 464 if ($returnvalue) 465 { 466 $infoline = "ERROR: Could not execute $msidb!\n"; 467 $installer::logger::Lang->print($infoline); 468 } 469 else 470 { 471 $infoline = "Success: Executed $msidb successfully!\n"; 472 $installer::logger::Lang->print($infoline); 473 } 474} 475 476##################################################################### 477# Returning the value from sis.mlf for Summary Information Stream 478##################################################################### 479 480sub get_value_from_sis_lng 481{ 482 my ($language, $languagefile, $searchstring) = @_; 483 484 my $language_block = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $languagefile); 485 my $newstring = installer::windows::idtglobal::get_language_string_from_language_block($language_block, $language, $searchstring); 486 $newstring = "\"" . $newstring . "\""; 487 488 return $newstring; 489} 490 491################################################################# 492# Returning the msi version for the Summary Information Stream 493################################################################# 494 495sub get_msiversion_for_sis 496{ 497 my $msiversion = "200"; 498 return $msiversion; 499} 500 501################################################################# 502# Returning the word count for the Summary Information Stream 503################################################################# 504 505sub get_wordcount_for_sis 506{ 507 my $wordcount = "0"; 508 return $wordcount; 509} 510 511################################################################# 512# Returning the codepage for the Summary Information Stream 513################################################################# 514 515sub get_codepage_for_sis 516{ 517 my ( $language ) = @_; 518 519 my $codepage = installer::windows::language::get_windows_encoding($language); 520 521 # Codepage 65001 does not work in Summary Information Stream 522 if ( $codepage == 65001 ) { $codepage = 0; } 523 524 # my $codepage = "1252"; # determine dynamically in a function 525 # my $codepage = "65001"; # UTF-8 526 return $codepage; 527} 528 529################################################################# 530# Returning the template for the Summary Information Stream 531################################################################# 532 533sub get_template_for_sis 534{ 535 my ( $language, $allvariables ) = @_; 536 537 my $windowslanguage = installer::windows::language::get_windows_language($language); 538 539 my $architecture = "Intel"; 540 541 # Adding 256, if this is a 64 bit installation set. 542 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) { $architecture = "x64"; } 543 544 my $value = "\"" . $architecture . ";" . $windowslanguage; # adding the Windows language 545 546 $value = $value . "\""; # adding ending '"' 547 548 return $value ; 549} 550 551################################################################# 552# Returning the PackageCode for the Summary Information Stream 553################################################################# 554 555sub get_packagecode_for_sis 556{ 557 # always generating a new package code for each package 558 559 my $guidref = get_guid_list(1, 1); # only one GUID shall be generated 560 561 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces 562 563 my $guid = "\{" . ${$guidref}[0] . "\}"; 564 565 my $infoline = "PackageCode: $guid\n"; 566 $installer::logger::Lang->print($infoline); 567 568 return $guid; 569} 570 571################################################################# 572# Returning the title for the Summary Information Stream 573################################################################# 574 575sub get_title_for_sis 576{ 577 my ( $language, $languagefile, $searchstring ) = @_; 578 579 my $title = get_value_from_sis_lng($language, $languagefile, $searchstring ); 580 581 return $title; 582} 583 584################################################################# 585# Returning the author for the Summary Information Stream 586################################################################# 587 588sub get_author_for_sis 589{ 590 my $author = $installer::globals::longmanufacturer; 591 592 $author = "\"" . $author . "\""; 593 594 return $author; 595} 596 597################################################################# 598# Returning the subject for the Summary Information Stream 599################################################################# 600 601sub get_subject_for_sis 602{ 603 my ( $allvariableshashref ) = @_; 604 605 my $subject = $allvariableshashref->{'PRODUCTNAME'} . " " . $allvariableshashref->{'PRODUCTVERSION'}; 606 607 $subject = "\"" . $subject . "\""; 608 609 return $subject; 610} 611 612################################################################# 613# Returning the comment for the Summary Information Stream 614################################################################# 615 616sub get_comment_for_sis 617{ 618 my ( $language, $languagefile, $searchstring ) = @_; 619 620 my $comment = get_value_from_sis_lng($language, $languagefile, $searchstring ); 621 622 return $comment; 623} 624 625################################################################# 626# Returning the keywords for the Summary Information Stream 627################################################################# 628 629sub get_keywords_for_sis 630{ 631 my ( $language, $languagefile, $searchstring ) = @_; 632 633 my $keywords = get_value_from_sis_lng($language, $languagefile, $searchstring ); 634 635 return $keywords; 636} 637 638###################################################################### 639# Returning the application name for the Summary Information Stream 640###################################################################### 641 642sub get_appname_for_sis 643{ 644 my ( $language, $languagefile, $searchstring ) = @_; 645 646 my $appname = get_value_from_sis_lng($language, $languagefile, $searchstring ); 647 648 return $appname; 649} 650 651###################################################################### 652# Returning the security for the Summary Information Stream 653###################################################################### 654 655sub get_security_for_sis 656{ 657 my $security = "0"; 658 return $security; 659} 660 661################################################################# 662# Writing the Summary information stream into the msi database 663# This works only on Windows 664################################################################# 665 666sub write_summary_into_msi_database 667{ 668 my ($msifilename, $language, $languagefile, $allvariableshashref) = @_; 669 670 # -g : requrired msi version 671 # -c : codepage 672 # -p : template 673 674 installer::logger::include_header_into_logfile("Writing summary information stream"); 675 676 my $msiinfo = "msiinfo.exe"; # Has to be in the path 677 678 my $sislanguage = "en-US"; # title, comment, keyword and appname alway in english 679 680 my $msiversion = get_msiversion_for_sis(); 681 my $codepage = get_codepage_for_sis($language); 682 my $template = get_template_for_sis($language, $allvariableshashref); 683 my $guid = get_packagecode_for_sis(); 684 my $title = get_title_for_sis($sislanguage,$languagefile, "OOO_SIS_TITLE"); 685 my $author = get_author_for_sis(); 686 my $subject = get_subject_for_sis($allvariableshashref); 687 my $comment = get_comment_for_sis($sislanguage,$languagefile, "OOO_SIS_COMMENT"); 688 my $keywords = get_keywords_for_sis($sislanguage,$languagefile, "OOO_SIS_KEYWORDS"); 689 my $appname = get_appname_for_sis($sislanguage,$languagefile, "OOO_SIS_APPNAME"); 690 my $security = get_security_for_sis(); 691 my $wordcount = get_wordcount_for_sis(); 692 693 $msifilename = installer::converter::make_path_conform($msifilename); 694 695 my $systemcall = $msiinfo . " " . $msifilename . " -g " . $msiversion . " -c " . $codepage 696 . " -p " . $template . " -v " . $guid . " -t " . $title . " -a " . $author 697 . " -j " . $subject . " -o " . $comment . " -k " . $keywords . " -n " . $appname 698 . " -u " . $security . " -w " . $wordcount; 699 700 my $returnvalue = system($systemcall); 701 702 my $infoline = "Systemcall: $systemcall\n"; 703 $installer::logger::Lang->print($infoline); 704 705 if ($returnvalue) 706 { 707 $infoline = "ERROR: Could not execute $msiinfo!\n"; 708 $installer::logger::Lang->print($infoline); 709 } 710 else 711 { 712 $infoline = "Success: Executed $msiinfo successfully!\n"; 713 $installer::logger::Lang->print($infoline); 714 } 715} 716 717######################################################################### 718# For more than one language in the installation set: 719# Use one database and create Transformations for all other languages 720######################################################################### 721 722sub create_transforms 723{ 724 my ($languagesarray, $defaultlanguage, $installdir, $allvariableshashref) = @_; 725 726 installer::logger::include_header_into_logfile("Creating Transforms"); 727 728 my $msitran = "msitran.exe"; # Has to be in the path 729 730 $installdir = installer::converter::make_path_conform($installdir); 731 732 # Syntax for creating a transformation 733 # msitran.exe -g <baseDB> <referenceDB> <transformfile> [<errorhandling>} 734 735 my $basedbname = get_msidatabasename($allvariableshashref, $defaultlanguage); 736 $basedbname = $installdir . $installer::globals::separator . $basedbname; 737 738 my $errorhandling = "f"; # Suppress "change codepage" error 739 740 # Iterating over all files 741 742 foreach ( @{$languagesarray} ) 743 { 744 my $onelanguage = $_; 745 746 if ( $onelanguage eq $defaultlanguage ) { next; } 747 748 my $referencedbname = get_msidatabasename($allvariableshashref, $onelanguage); 749 $referencedbname = $installdir . $installer::globals::separator . $referencedbname; 750 751 my $transformfile = $installdir . $installer::globals::separator . "trans_" . $onelanguage . ".mst"; 752 753 my $systemcall = $msitran . " " . " -g " . $basedbname . " " . $referencedbname . " " . $transformfile . " " . $errorhandling; 754 755 my $returnvalue = system($systemcall); 756 757 my $infoline = "Systemcall: $systemcall\n"; 758 $installer::logger::Lang->print($infoline); 759 760 # Problem: msitran.exe in version 4.0 always returns "1", even if no failure occured. 761 # Therefore it has to be checked, if this is version 4.0. If yes, if the mst file 762 # exists and if it is larger than 0 bytes. If this is true, then no error occured. 763 # File Version of msitran.exe: 4.0.6000.16384 has checksum: "b66190a70145a57773ec769e16777b29". 764 # Same for msitran.exe from wntmsci12: "aa25d3445b94ffde8ef0c1efb77a56b8" 765 766 if ($returnvalue) 767 { 768 $infoline = "WARNING: Returnvalue of $msitran is not 0. Checking version of $msitran!\n"; 769 $installer::logger::Lang->print($infoline); 770 771 open(FILE, "<$installer::globals::msitranpath") or die "ERROR: Can't open $installer::globals::msitranpath for creating file hash"; 772 binmode(FILE); 773 my $digest = Digest::MD5->new->addfile(*FILE)->hexdigest; 774 close(FILE); 775 776 my @problemchecksums = ("b66190a70145a57773ec769e16777b29", "aa25d3445b94ffde8ef0c1efb77a56b8"); 777 my $isproblemchecksum = 0; 778 779 foreach my $problemchecksum ( @problemchecksums ) 780 { 781 $infoline = "Checksum of problematic MsiTran.exe: $problemchecksum\n"; 782 $installer::logger::Lang->print($infoline); 783 $infoline = "Checksum of used MsiTran.exe: $digest\n"; 784 $installer::logger::Lang->print($infoline); 785 if ( $digest eq $problemchecksum ) { $isproblemchecksum = 1; } 786 } 787 788 if ( $isproblemchecksum ) 789 { 790 # Check existence of mst 791 if ( -f $transformfile ) 792 { 793 $infoline = "File $transformfile exists.\n"; 794 $installer::logger::Lang->print($infoline); 795 my $filesize = ( -s $transformfile ); 796 $infoline = "Size of $transformfile: $filesize\n"; 797 $installer::logger::Lang->print($infoline); 798 799 if ( $filesize > 0 ) 800 { 801 $infoline = "Info: Returnvalue $returnvalue of $msitran is no problem :-) .\n"; 802 $installer::logger::Lang->print($infoline); 803 $returnvalue = 0; # reset the error 804 } 805 else 806 { 807 $infoline = "Filesize indicates that an error occured.\n"; 808 $installer::logger::Lang->print($infoline); 809 } 810 } 811 else 812 { 813 $infoline = "File $transformfile does not exist -> An error occured.\n"; 814 $installer::logger::Lang->print($infoline); 815 } 816 } 817 else 818 { 819 $infoline = "This is not a problematic version of msitran.exe. Therefore the error is not caused by problematic msitran.exe.\n"; 820 $installer::logger::Lang->print($infoline); 821 } 822 } 823 824 if ($returnvalue) 825 { 826 $infoline = "ERROR: Could not execute $msitran!\n"; 827 $installer::logger::Lang->print($infoline); 828 } 829 else 830 { 831 $infoline = "Success: Executed $msitran successfully!\n"; 832 $installer::logger::Lang->print($infoline); 833 } 834 835 # The reference database can be deleted 836 837 my $result = unlink($referencedbname); 838 # $result contains the number of deleted files 839 840 if ( $result == 0 ) 841 { 842 $infoline = "ERROR: Could not remove file $$referencedbname !\n"; 843 $installer::logger::Lang->print($infoline); 844 installer::exiter::exit_program($infoline, "create_transforms"); 845 } 846 } 847} 848 849######################################################################### 850# The default language msi database does not need to contain 851# the language in the database name. Therefore the file 852# is renamed. Example: "openofficeorg20_01.msi" to "openofficeorg20.msi" 853######################################################################### 854 855sub rename_msi_database_in_installset 856{ 857 my ($defaultlanguage, $installdir, $allvariableshashref) = @_; 858 859 installer::logger::include_header_into_logfile("Renaming msi database"); 860 861 my $olddatabasename = get_msidatabasename($allvariableshashref, $defaultlanguage); 862 $olddatabasename = $installdir . $installer::globals::separator . $olddatabasename; 863 864 my $newdatabasename = get_msidatabasename($allvariableshashref); 865 866 $installer::globals::shortmsidatabasename = $newdatabasename; 867 868 $newdatabasename = $installdir . $installer::globals::separator . $newdatabasename; 869 870 installer::systemactions::rename_one_file($olddatabasename, $newdatabasename); 871 872 $installer::globals::msidatabasename = $newdatabasename; 873} 874 875######################################################################### 876# Adding the language to the name of the msi databasename, 877# if this is required (ADDLANGUAGEINDATABASENAME) 878######################################################################### 879 880sub add_language_to_msi_database 881{ 882 my ($defaultlanguage, $installdir, $allvariables) = @_; 883 884 my $languagestring = $defaultlanguage; 885 if ( $allvariables->{'USELANGUAGECODE'} ) { $languagestring = installer::windows::language::get_windows_language($defaultlanguage); } 886 my $newdatabasename = $installer::globals::shortmsidatabasename; 887 $newdatabasename =~ s/\.msi\s*$/_$languagestring\.msi/; 888 $installer::globals::shortmsidatabasename = $newdatabasename; 889 $newdatabasename = $installdir . $installer::globals::separator . $newdatabasename; 890 891 my $olddatabasename = $installer::globals::msidatabasename; 892 893 installer::systemactions::rename_one_file($olddatabasename, $newdatabasename); 894 895 $installer::globals::msidatabasename = $newdatabasename; 896} 897 898########################################################################## 899# Writing the databasename into the setup.ini. 900########################################################################## 901 902sub put_databasename_into_setupini 903{ 904 my ($setupinifile, $allvariableshashref) = @_; 905 906 my $databasename = get_msidatabasename($allvariableshashref); 907 my $line = "database=" . $databasename . "\n"; 908 909 push(@{$setupinifile}, $line); 910} 911 912########################################################################## 913# Writing the required msi version into setup.ini 914########################################################################## 915 916sub put_msiversion_into_setupini 917{ 918 my ($setupinifile) = @_; 919 920 my $msiversion = "2.0"; 921 my $line = "msiversion=" . $msiversion . "\n"; 922 923 push(@{$setupinifile}, $line); 924} 925 926########################################################################## 927# Writing the productname into setup.ini 928########################################################################## 929 930sub put_productname_into_setupini 931{ 932 my ($setupinifile, $allvariableshashref) = @_; 933 934 my $productname = $allvariableshashref->{'PRODUCTNAME'}; 935 my $line = "productname=" . $productname . "\n"; 936 937 push(@{$setupinifile}, $line); 938} 939 940########################################################################## 941# Writing the productcode into setup.ini 942########################################################################## 943 944sub put_productcode_into_setupini 945{ 946 my ($setupinifile) = @_; 947 948 my $productcode = $installer::globals::productcode; 949 my $line = "productcode=" . $productcode . "\n"; 950 951 push(@{$setupinifile}, $line); 952} 953 954########################################################################## 955# Writing the ProductVersion from Property table into setup.ini 956########################################################################## 957 958sub put_productversion_into_setupini 959{ 960 my ($setupinifile) = @_; 961 962 my $line = "productversion=" . $installer::globals::msiproductversion . "\n"; 963 push(@{$setupinifile}, $line); 964} 965 966########################################################################## 967# Writing the key for Minor Upgrades into setup.ini 968########################################################################## 969 970sub put_upgradekey_into_setupini 971{ 972 my ($setupinifile) = @_; 973 974 if ( $installer::globals::minorupgradekey ne "" ) 975 { 976 my $line = "upgradekey=" . $installer::globals::minorupgradekey . "\n"; 977 push(@{$setupinifile}, $line); 978 } 979} 980 981########################################################################## 982# Writing the number of languages into setup.ini 983########################################################################## 984 985sub put_languagecount_into_setupini 986{ 987 my ($setupinifile, $languagesarray) = @_; 988 989 my $languagecount = $#{$languagesarray} + 1; 990 my $line = "count=" . $languagecount . "\n"; 991 992 push(@{$setupinifile}, $line); 993} 994 995########################################################################## 996# Writing the defaultlanguage into setup.ini 997########################################################################## 998 999sub put_defaultlanguage_into_setupini 1000{ 1001 my ($setupinifile, $defaultlanguage) = @_; 1002 1003 my $windowslanguage = installer::windows::language::get_windows_language($defaultlanguage); 1004 my $line = "default=" . $windowslanguage . "\n"; 1005 push(@{$setupinifile}, $line); 1006} 1007 1008########################################################################## 1009# Writing the information about transformations into setup.ini 1010########################################################################## 1011 1012sub put_transforms_into_setupini 1013{ 1014 my ($setupinifile, $onelanguage, $counter) = @_; 1015 1016 my $windowslanguage = installer::windows::language::get_windows_language($onelanguage); 1017 my $transformfilename = "trans_" . $onelanguage . ".mst"; 1018 1019 my $line = "lang" . $counter . "=" . $windowslanguage . "," . $transformfilename . "\n"; 1020 1021 push(@{$setupinifile}, $line); 1022} 1023 1024################################################### 1025# Including Windows line ends in ini files 1026# Profiles on Windows shall have \r\n line ends 1027################################################### 1028 1029sub include_windows_lineends 1030{ 1031 my ($onefile) = @_; 1032 1033 for ( my $i = 0; $i <= $#{$onefile}; $i++ ) 1034 { 1035 ${$onefile}[$i] =~ s/\r?\n$/\r\n/; 1036 } 1037} 1038 1039########################################################################## 1040# Generation the file setup.ini, that is used by the loader setup.exe. 1041########################################################################## 1042 1043sub create_setup_ini 1044{ 1045 my ($languagesarray, $defaultlanguage, $installdir, $allvariableshashref) = @_; 1046 1047 installer::logger::include_header_into_logfile("Creating setup.ini"); 1048 1049 my $setupinifilename = $installdir . $installer::globals::separator . "setup.ini"; 1050 1051 my @setupinifile = (); 1052 my $setupinifile = \@setupinifile; 1053 1054 my $line = "\[setup\]\n"; 1055 push(@setupinifile, $line); 1056 1057 put_databasename_into_setupini($setupinifile, $allvariableshashref); 1058 put_msiversion_into_setupini($setupinifile); 1059 put_productname_into_setupini($setupinifile, $allvariableshashref); 1060 put_productcode_into_setupini($setupinifile); 1061 put_productversion_into_setupini($setupinifile); 1062 put_upgradekey_into_setupini($setupinifile); 1063 1064 $line = "\[languages\]\n"; 1065 push(@setupinifile, $line); 1066 1067 put_languagecount_into_setupini($setupinifile, $languagesarray); 1068 put_defaultlanguage_into_setupini($setupinifile, $defaultlanguage); 1069 1070 if ( $#{$languagesarray} > 0 ) # writing the transforms information 1071 { 1072 my $counter = 1; 1073 1074 for ( my $i = 0; $i <= $#{$languagesarray}; $i++ ) 1075 { 1076 if ( ${$languagesarray}[$i] eq $defaultlanguage ) { next; } 1077 1078 put_transforms_into_setupini($setupinifile, ${$languagesarray}[$i], $counter); 1079 $counter++; 1080 } 1081 } 1082 1083 if ( $installer::globals::iswin && $installer::globals::plat =~ /cygwin/i) # Windows line ends only for Cygwin 1084 { 1085 include_windows_lineends($setupinifile); 1086 } 1087 1088 installer::files::save_file($setupinifilename, $setupinifile); 1089 1090 $infoline = "Generated file $setupinifilename !\n"; 1091 $installer::logger::Lang->print($infoline); 1092} 1093 1094################################################################# 1095# Copying the files defined as ScpActions into the 1096# installation set. 1097################################################################# 1098 1099sub copy_scpactions_into_installset 1100{ 1101 my ($defaultlanguage, $installdir, $allscpactions) = @_; 1102 1103 installer::logger::include_header_into_logfile("Copying ScpAction files into installation set"); 1104 1105 for ( my $i = 0; $i <= $#{$allscpactions}; $i++ ) 1106 { 1107 my $onescpaction = ${$allscpactions}[$i]; 1108 1109 if ( $onescpaction->{'Name'} eq "loader.exe" ) { next; } # do not copy this ScpAction loader 1110 1111 # only copying language independent files or files with the correct language (the defaultlanguage) 1112 1113 my $filelanguage = $onescpaction->{'specificlanguage'}; 1114 1115 if ( ($filelanguage eq $defaultlanguage) || ($filelanguage eq "") ) 1116 { 1117 my $sourcefile = $onescpaction->{'sourcepath'}; 1118 my $destfile = $installdir . $installer::globals::separator . $onescpaction->{'DestinationName'}; 1119 1120 installer::systemactions::copy_one_file($sourcefile, $destfile); 1121 } 1122 } 1123} 1124 1125################################################################# 1126# Copying the files for the Windows installer into the 1127# installation set (setup.exe). 1128################################################################# 1129 1130sub copy_windows_installer_files_into_installset 1131{ 1132 my ($installdir, $includepatharrayref, $allvariables) = @_; 1133 1134 installer::logger::include_header_into_logfile("Copying Windows installer files into installation set"); 1135 1136 @copyfile = (); 1137 push(@copyfile, "loader2.exe"); 1138 1139 if ( $allvariables->{'NOLOADERREQUIRED'} ) { @copyfile = (); } 1140 1141 for ( my $i = 0; $i <= $#copyfile; $i++ ) 1142 { 1143 my $filename = $copyfile[$i]; 1144 my $sourcefileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1); 1145 1146 if ( ! -f $$sourcefileref ) { installer::exiter::exit_program("ERROR: msi file not found: $$sourcefileref !", "copy_windows_installer_files_into_installset"); } 1147 1148 my $destfile; 1149 if ( $copyfile[$i] eq "loader2.exe" ) { $destfile = "setup.exe"; } # renaming the loader 1150 else { $destfile = $copyfile[$i]; } 1151 1152 $destfile = $installdir . $installer::globals::separator . $destfile; 1153 1154 installer::systemactions::copy_one_file($$sourcefileref, $destfile); 1155 } 1156} 1157 1158################################################################# 1159# Copying the child projects into the 1160# installation set 1161################################################################# 1162 1163sub copy_child_projects_into_installset 1164{ 1165 my ($installdir, $allvariables) = @_; 1166 1167 my $sourcefile = ""; 1168 my $destdir = ""; 1169 1170 # adding Java 1171 1172 if ( $allvariables->{'JAVAPRODUCT'} ) 1173 { 1174 $sourcefile = $installer::globals::javafile->{'sourcepath'}; 1175 $destdir = $installdir . $installer::globals::separator . $installer::globals::javafile->{'Subdir'}; 1176 if ( ! -d $destdir) { installer::systemactions::create_directory($destdir); } 1177 installer::systemactions::copy_one_file($sourcefile, $destdir); 1178 } 1179 1180 if ( $allvariables->{'UREPRODUCT'} ) 1181 { 1182 $sourcefile = $installer::globals::urefile->{'sourcepath'}; 1183 $destdir = $installdir . $installer::globals::separator . $installer::globals::urefile->{'Subdir'}; 1184 if ( ! -d $destdir) { installer::systemactions::create_directory($destdir); } 1185 installer::systemactions::copy_one_file($sourcefile, $destdir); 1186 } 1187} 1188 1189################################################################# 1190# Getting a list of GUID using uuidgen.exe. 1191# This works only on Windows 1192################################################################# 1193 1194sub get_guid_list 1195{ 1196 my ($number, $log) = @_; 1197 1198 if ( $log ) { installer::logger::include_header_into_logfile("Generating $number GUID"); } 1199 1200 my $uuidgen = "uuidgen.exe"; # Has to be in the path 1201 1202 # "-c" for uppercase output 1203 1204 # my $systemcall = "$uuidgen -n$number -c |"; 1205 my $systemcall = "$uuidgen -n$number |"; 1206 open (UUIDGEN, "$systemcall" ) or die("uuidgen is missing."); 1207 my @uuidlist = <UUIDGEN>; 1208 close (UUIDGEN); 1209 1210 my $infoline = "Systemcall: $systemcall\n"; 1211 if ( $log ) { $installer::logger::Lang->print($infoline); } 1212 1213 my $comparenumber = $#uuidlist + 1; 1214 1215 if ( $comparenumber == $number ) 1216 { 1217 $infoline = "Success: Executed $uuidgen successfully!\n"; 1218 if ( $log ) { $installer::logger::Lang->print($infoline); } 1219 } 1220 else 1221 { 1222 $infoline = "ERROR: Could not execute $uuidgen successfully!\n"; 1223 if ( $log ) { $installer::logger::Lang->print($infoline); } 1224 } 1225 1226 # uppercase, no longer "-c", because this is only supported in uuidgen.exe v.1.01 1227 for ( my $i = 0; $i <= $#uuidlist; $i++ ) { $uuidlist[$i] = uc($uuidlist[$i]); } 1228 1229 return \@uuidlist; 1230} 1231 1232################################################################# 1233# Calculating a GUID with a string using md5. 1234################################################################# 1235 1236sub calculate_guid 1237{ 1238 my ( $string ) = @_; 1239 1240 my $guid = ""; 1241 1242 my $md5 = Digest::MD5->new; 1243 $md5->add($string); 1244 my $digest = $md5->hexdigest; 1245 $digest = uc($digest); 1246 1247 # my $id = pack("A32", $digest); 1248 my ($first, $second, $third, $fourth, $fifth) = unpack ('A8 A4 A4 A4 A12', $digest); 1249 $guid = "$first-$second-$third-$fourth-$fifth"; 1250 1251 return $guid; 1252} 1253 1254################################################################# 1255# Calculating a ID with a string using md5 (very fast). 1256################################################################# 1257 1258sub calculate_id 1259{ 1260 my ( $string, $length ) = @_; 1261 1262 my $id = ""; 1263 1264 my $md5 = Digest::MD5->new; 1265 $md5->add($string); 1266 my $digest = lc($md5->hexdigest); 1267 $id = substr($digest, 0, $length); 1268 1269 return $id; 1270} 1271 1272################################################################# 1273# Filling the component hash with the values of the 1274# component file. 1275################################################################# 1276 1277sub fill_component_hash 1278{ 1279 my ($componentfile) = @_; 1280 1281 my %components = (); 1282 1283 for ( my $i = 0; $i <= $#{$componentfile}; $i++ ) 1284 { 1285 my $line = ${$componentfile}[$i]; 1286 1287 if ( $line =~ /^\s*(.*?)\t(.*?)\s*$/ ) 1288 { 1289 my $key = $1; 1290 my $value = $2; 1291 1292 $components{$key} = $value; 1293 } 1294 } 1295 1296 return \%components; 1297} 1298 1299################################################################# 1300# Creating a new component file, if new guids were generated. 1301################################################################# 1302 1303sub create_new_component_file 1304{ 1305 my ($componenthash) = @_; 1306 1307 my @componentfile = (); 1308 1309 my $key; 1310 1311 foreach $key (keys %{$componenthash}) 1312 { 1313 my $value = $componenthash->{$key}; 1314 my $input = "$key\t$value\n"; 1315 push(@componentfile ,$input); 1316 } 1317 1318 return \@componentfile; 1319} 1320 1321################################################################# 1322# Filling real component GUID into the component table. 1323# This works only on Windows 1324################################################################# 1325 1326sub set_uuid_into_component_table 1327{ 1328 my ($idtdirbase, $allvariables) = @_; 1329 1330 my $componenttablename = $idtdirbase . $installer::globals::separator . "Componen.idt"; 1331 1332 my $componenttable = installer::files::read_file($componenttablename); 1333 1334 # For update and patch reasons (small update) the GUID of an existing component must not change! 1335 # The collection of component GUIDs is saved in the directory $installer::globals::idttemplatepath in the file "components.txt" 1336 1337 my $infoline = ""; 1338 my $counter = 0; 1339 # my $componentfile = installer::files::read_file($installer::globals::componentfilename); 1340 # my $componenthash = fill_component_hash($componentfile); 1341 1342 for ( my $i = 3; $i <= $#{$componenttable}; $i++ ) # ignoring the first three lines 1343 { 1344 my $oneline = ${$componenttable}[$i]; 1345 my $componentname = ""; 1346 if ( $oneline =~ /^\s*(\S+?)\t/ ) { $componentname = $1; } 1347 1348 my $uuid = ""; 1349 1350 # if ( $componenthash->{$componentname} ) 1351 # { 1352 # $uuid = $componenthash->{$componentname}; 1353 # } 1354 # else 1355 # { 1356 1357 if ( exists($installer::globals::calculated_component_guids{$componentname})) 1358 { 1359 $uuid = $installer::globals::calculated_component_guids{$componentname}; 1360 } 1361 else 1362 { 1363 # Calculating new GUID with the help of the component name. 1364 my $useooobaseversion = 1; 1365 if ( exists($installer::globals::base_independent_components{$componentname})) { $useooobaseversion = 0; } 1366 my $sourcestring = $componentname; 1367 1368 if ( $useooobaseversion ) 1369 { 1370 if ( ! exists($allvariables->{'OOOBASEVERSION'}) ) { installer::exiter::exit_program("ERROR: Could not find variable \"OOOBASEVERSION\" (required value for GUID creation)!", "set_uuid_into_component_table"); } 1371 $sourcestring = $sourcestring . "_" . $allvariables->{'OOOBASEVERSION'}; 1372 } 1373 $uuid = calculate_guid($sourcestring); 1374 $counter++; 1375 1376 # checking, if there is a conflict with an already created guid 1377 if ( exists($installer::globals::allcalculated_guids{$uuid}) ) { installer::exiter::exit_program("ERROR: \"$uuid\" was already created before!", "set_uuid_into_component_table"); } 1378 $installer::globals::allcalculated_guids{$uuid} = 1; 1379 $installer::globals::calculated_component_guids{$componentname} = $uuid; 1380 1381 # Setting new uuid 1382 # $componenthash->{$componentname} = $uuid; 1383 1384 # Setting flag 1385 # $installer::globals::created_new_component_guid = 1; # this is very important! 1386 } 1387 # } 1388 1389 ${$componenttable}[$i] =~ s/COMPONENTGUID/$uuid/; 1390 } 1391 1392 installer::files::save_file($componenttablename, $componenttable); 1393 1394# if ( $installer::globals::created_new_component_guid ) 1395# { 1396# # create new component file! 1397# $componentfile = create_new_component_file($componenthash); 1398# installer::worker::sort_array($componentfile); 1399# 1400# # To avoid conflict the components file cannot be saved at the same place 1401# # All important data have to be saved in the directory: $installer::globals::infodirectory 1402# my $localcomponentfilename = $installer::globals::componentfilename; 1403# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$localcomponentfilename); 1404# $localcomponentfilename = $installer::globals::infodirectory . $installer::globals::separator . $localcomponentfilename; 1405# installer::files::save_file($localcomponentfilename, $componentfile); 1406# 1407# # installer::files::save_file($installer::globals::componentfilename, $componentfile); # version using new file in solver 1408# 1409# $infoline = "COMPONENTCODES: Created $counter new GUIDs for components ! \n"; 1410# $installer::logger::Lang->print($infoline); 1411# } 1412# else 1413# { 1414# $infoline = "SUCCESS COMPONENTCODES: All component codes exist! \n"; 1415# $installer::logger::Lang->print($infoline); 1416# } 1417 1418} 1419 1420######################################################################### 1421# Adding final 64 properties into msi database, if required. 1422# RegLocator : +16 in type column to search in 64 bit registry. 1423# All conditions: "VersionNT" -> "VersionNT64" (several tables). 1424# Already done: "+256" in Attributes column of table "Component". 1425# Still following: Setting "x64" instead of "Intel" in Summary 1426# Information Stream of msi database in "get_template_for_sis". 1427######################################################################### 1428 1429sub prepare_64bit_database 1430{ 1431 my ($basedir, $allvariables) = @_; 1432 1433 my $infoline = ""; 1434 1435 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) 1436 { 1437 # 1. Beginning with table "RegLocat.idt". Adding "16" to the type. 1438 1439 my $reglocatfile = ""; 1440 my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt"; 1441 1442 if ( -f $reglocatfilename ) 1443 { 1444 my $saving_required = 0; 1445 $reglocatfile = installer::files::read_file($reglocatfilename); 1446 1447 for ( my $i = 3; $i <= $#{$reglocatfile}; $i++ ) # ignoring the first three lines 1448 { 1449 my $oneline = ${$reglocatfile}[$i]; 1450 1451 if ( $oneline =~ /^\s*\#/ ) { next; } # this is a comment line 1452 if ( $oneline =~ /^\s*$/ ) { next; } 1453 1454 if ( $oneline =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(\d+)\s*$/ ) 1455 { 1456 # Syntax: Signature_ Root Key Name Type 1457 my $sig = $1; 1458 my $root = $2; 1459 my $key = $3; 1460 my $name = $4; 1461 my $type = $5; 1462 1463 $type = $type + 16; 1464 1465 my $newline = $sig . "\t" . $root . "\t" . $key . "\t" . $name . "\t" . $type . "\n"; 1466 ${$reglocatfile}[$i] = $newline; 1467 1468 $saving_required = 1; 1469 } 1470 } 1471 1472 if ( $saving_required ) 1473 { 1474 # Saving the files 1475 installer::files::save_file($reglocatfilename ,$reglocatfile); 1476 $infoline = "Making idt file 64 bit conform: $reglocatfilename\n"; 1477 $installer::logger::Lang->print($infoline); 1478 } 1479 } 1480 1481 # 2. Replacing all occurences of "VersionNT" by "VersionNT64" 1482 1483 my @versionnt_files = ("Componen.idt", "InstallE.idt", "InstallU.idt", "LaunchCo.idt"); 1484 1485 foreach my $onefile ( @versionnt_files ) 1486 { 1487 my $fullfilename = $basedir . $installer::globals::separator . $onefile; 1488 1489 if ( -f $fullfilename ) 1490 { 1491 my $saving_required = 0; 1492 $filecontent = installer::files::read_file($fullfilename); 1493 1494 for ( my $i = 3; $i <= $#{$filecontent}; $i++ ) # ignoring the first three lines 1495 { 1496 my $oneline = ${$filecontent}[$i]; 1497 1498 if ( $oneline =~ /\bVersionNT\b/ ) 1499 { 1500 ${$filecontent}[$i] =~ s/\bVersionNT\b/VersionNT64/g; 1501 $saving_required = 1; 1502 } 1503 } 1504 1505 if ( $saving_required ) 1506 { 1507 # Saving the files 1508 installer::files::save_file($fullfilename ,$filecontent); 1509 $infoline = "Making idt file 64 bit conform: $fullfilename\n"; 1510 $installer::logger::Lang->print($infoline); 1511 } 1512 } 1513 } 1514 } 1515 1516} 1517 1518################################################################# 1519# Include all cab files into the msi database. 1520# This works only on Windows 1521################################################################# 1522 1523sub include_cabs_into_msi 1524{ 1525 my ($installdir) = @_; 1526 1527 installer::logger::include_header_into_logfile("Including cabs into msi database"); 1528 1529 my $from = cwd(); 1530 my $to = $installdir; 1531 1532 chdir($to); 1533 1534 my $infoline = "Changing into directory: $to"; 1535 $installer::logger::Lang->print($infoline); 1536 1537 my $msidb = "msidb.exe"; # Has to be in the path 1538 my $extraslash = ""; # Has to be set for non-ActiveState perl 1539 1540 my $msifilename = $installer::globals::msidatabasename; 1541 1542 $msifilename = installer::converter::make_path_conform($msifilename); 1543 1544 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 1545 $msifilename =~ s/\//\\\\/g; 1546 $extraslash = "\\"; 1547 1548 my $allcabfiles = installer::systemactions::find_file_with_file_extension("cab", $installdir); 1549 1550 for ( my $i = 0; $i <= $#{$allcabfiles}; $i++ ) 1551 { 1552 my $systemcall = $msidb . " -d " . $msifilename . " -a " . ${$allcabfiles}[$i]; 1553 1554 my $returnvalue = system($systemcall); 1555 1556 $infoline = "Systemcall: $systemcall\n"; 1557 $installer::logger::Lang->print($infoline); 1558 1559 if ($returnvalue) 1560 { 1561 $infoline = "ERROR: Could not execute $systemcall !\n"; 1562 $installer::logger::Lang->print($infoline); 1563 } 1564 else 1565 { 1566 $infoline = "Success: Executed $systemcall successfully!\n"; 1567 $installer::logger::Lang->print($infoline); 1568 } 1569 1570 # deleting the cab file 1571 1572 unlink(${$allcabfiles}[$i]); 1573 1574 $infoline = "Deleted cab file: ${$allcabfiles}[$i]\n"; 1575 $installer::logger::Lang->print($infoline); 1576 } 1577 1578 $infoline = "Changing back into directory: $from"; 1579 $installer::logger::Lang->print($infoline); 1580 1581 chdir($from); 1582} 1583 1584################################################################# 1585# Executing the created batch file to pack all files. 1586# This works only on Windows 1587################################################################# 1588 1589sub execute_packaging 1590{ 1591 my ($localpackjobref, $loggingdir, $allvariables) = @_; 1592 1593 installer::logger::include_header_into_logfile("Packaging process"); 1594 1595 $installer::logger::Lang->add_timestamp("Performance Info: Execute packaging start"); 1596 1597 my $infoline = ""; 1598 my $from = cwd(); 1599 my $to = $loggingdir; 1600 1601 chdir($to); 1602 $infoline = "chdir: $to \n"; 1603 $installer::logger::Lang->print($infoline); 1604 1605 # if the ddf file contains relative pathes, it is necessary to change into the temp directory 1606 if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) 1607 { 1608 $to = $installer::globals::temppath; 1609 chdir($to); 1610 $infoline = "chdir: $to \n"; 1611 $installer::logger::Lang->print($infoline); 1612 } 1613 1614 # changing the tmp directory, because makecab.exe generates temporary cab files 1615 my $origtemppath = ""; 1616 if ( $ENV{'TMP'} ) { $origtemppath = $ENV{'TMP'}; } 1617 $ENV{'TMP'} = $installer::globals::temppath; # setting TMP to the new unique directory! 1618 1619 my $maxmakecabcalls = 3; 1620 my $allmakecabcalls = $#{$localpackjobref} + 1; 1621 1622 for ( my $i = 0; $i <= $#{$localpackjobref}; $i++ ) 1623 { 1624 my $systemcall = ${$localpackjobref}[$i]; 1625 1626 my $callscounter = $i + 1; 1627 1628 $installer::logger::Info->printf("... makecab.exe (%s/%s) ... \n", $callscounter, $allmakecabcalls); 1629 1630 # my $returnvalue = system($systemcall); 1631 1632 for ( my $n = 1; $n <= $maxmakecabcalls; $n++ ) 1633 { 1634 my @ddfoutput = (); 1635 1636 $infoline = "Systemcall: $systemcall"; 1637 $installer::logger::Lang->print($infoline); 1638 1639 open (DDF, "$systemcall"); 1640 while (<DDF>) {push(@ddfoutput, $_); } 1641 close (DDF); 1642 1643 my $returnvalue = $?; # $? contains the return value of the systemcall 1644 1645 if ($returnvalue) 1646 { 1647 if ( $n < $maxmakecabcalls ) 1648 { 1649 $installer::logger::Info->printf("makecab_error (Try %s): Trying again\n", $n); 1650 $installer::logger::Lang->printf("makecab_error (Try %s): Trying again\n", $n); 1651 } 1652 else 1653 { 1654 $installer::logger::Info->printf("ERROR (Try %s): Abort packing \n", $n); 1655 $installer::logger::Lang->printf("ERROR (Try %s): Abort packing \n", $n); 1656 } 1657 1658 for ( my $m = 0; $m <= $#ddfoutput; $m++ ) 1659 { 1660 if ( $ddfoutput[$m] =~ /(ERROR\:.*?)\s*$/ ) 1661 { 1662 $infoline = $1 . "\n"; 1663 if ( $n < $maxmakecabcalls ) 1664 { 1665 $infoline =~ s/ERROR\:/makecab_error\:/i; 1666 } 1667 $installer::logger::Info->print($infoline); 1668 $installer::logger::Lang->print($infoline); 1669 } 1670 } 1671 1672 if ( $n == $maxmakecabcalls ) { installer::exiter::exit_program("ERROR: \"$systemcall\"!", "execute_packaging"); } 1673 } 1674 else 1675 { 1676 $infoline = "Success (Try $n): $systemcall"; 1677 $installer::logger::Lang->print($infoline); 1678 last; 1679 } 1680 } 1681 } 1682 1683 $installer::logger::Lang->add_timestamp("Performance Info: Execute packaging end"); 1684 1685 # setting back to the original tmp directory 1686 $ENV{'TMP'} = $origtemppath; 1687 1688 chdir($from); 1689 $infoline = "chdir: $from \n"; 1690 $installer::logger::Lang->print($infoline); 1691} 1692 1693############################################################### 1694# Setting the global variables ProductCode and the UpgradeCode 1695############################################################### 1696 1697sub set_global_code_variables 1698{ 1699 my ( $languagesref, $languagestringref, $allvariableshashref, $alloldproperties ) = @_; 1700 1701 # In the msi template directory a files "codes.txt" has to exist, in which the ProductCode 1702 # and the UpgradeCode for the product are defined. 1703 # The name "codes.txt" can be overwritten in Product definition with CODEFILENAME . 1704 # Default $installer::globals::codefilename is defined in parameter.pm. 1705 1706 if ( $allvariableshashref->{'CODEFILENAME'} ) 1707 { 1708 $installer::globals::codefilename = $installer::globals::idttemplatepath . $installer::globals::separator . $allvariableshashref->{'CODEFILENAME'}; 1709 installer::files::check_file($installer::globals::codefilename); 1710 } 1711 1712 my $infoline = "Using Codes file: $installer::globals::codefilename \n"; 1713 $installer::logger::Lang->print($infoline); 1714 1715 my $codefile = installer::files::read_file($installer::globals::codefilename); 1716 1717 my $isopensource = 0; 1718 if ( $allvariableshashref->{'OPENSOURCE'} ) { $isopensource = $allvariableshashref->{'OPENSOURCE'}; } 1719 1720 my $onelanguage = ""; 1721 1722 if ( $#{$languagesref} > 0 ) # more than one language 1723 { 1724 if (( $installer::globals::added_english ) && ( $#{$languagesref} == 1 )) # only multilingual because of added English 1725 { 1726 $onelanguage = ${$languagesref}[1]; # setting the first language, that is not english 1727 } 1728 else 1729 { 1730 if (( ${$languagesref}[1] =~ /jp/ ) || 1731 ( ${$languagesref}[1] =~ /ko/ ) || 1732 ( ${$languagesref}[1] =~ /zh/ )) 1733 { 1734 $onelanguage = "multiasia"; 1735 } 1736 else 1737 { 1738 $onelanguage = "multiwestern"; 1739 } 1740 } 1741 } 1742 else # only one language 1743 { 1744 $onelanguage = ${$languagesref}[0]; 1745 } 1746 1747 # ProductCode must not change, if Windows patches shall be applied 1748 if ( $installer::globals::prepare_winpatch ) 1749 { 1750 # ProductCode has to be specified in each language 1751 my $searchstring = "PRODUCTCODE"; 1752 my $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile); 1753 $installer::globals::productcode = installer::windows::idtglobal::get_code_from_code_block($codeblock, $onelanguage); 1754 } else { 1755 my $guidref = get_guid_list(1, 1); # only one GUID shall be generated 1756 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces 1757 $installer::globals::productcode = "\{" . ${$guidref}[0] . "\}"; 1758 } 1759 1760 if ( $installer::globals::patch ) # patch upgrade codes are defined in soffice.lst 1761 { 1762 if ( $allvariableshashref->{'PATCHUPGRADECODE'} ) { $installer::globals::upgradecode = $allvariableshashref->{'PATCHUPGRADECODE'}; } 1763 else { installer::exiter::exit_program("ERROR: PATCHUPGRADECODE not defined in list file!", "set_global_code_variables"); } 1764 } 1765 else 1766 { 1767 # UpgradeCode can take english as default, if not defined in specified language 1768 1769 $searchstring = "UPGRADECODE"; # searching in the codes.txt file 1770 $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile); 1771 $installer::globals::upgradecode = installer::windows::idtglobal::get_language_string_from_language_block($codeblock, $onelanguage, ""); 1772 } 1773 1774 # if (( $installer::globals::productcode eq "" ) && ( ! $isopensource )) { installer::exiter::exit_program("ERROR: ProductCode for language $onelanguage not defined in $installer::globals::codefilename !", "set_global_code_variables"); } 1775 if ( $installer::globals::upgradecode eq "" ) { installer::exiter::exit_program("ERROR: UpgradeCode not defined in $installer::globals::codefilename !", "set_global_code_variables"); } 1776 1777 $infoline = "Setting ProductCode to: $installer::globals::productcode \n"; 1778 $installer::logger::Lang->print($infoline); 1779 $infoline = "Setting UpgradeCode to: $installer::globals::upgradecode \n"; 1780 $installer::logger::Lang->print($infoline); 1781 1782 # Adding both variables into the variables array 1783 1784 $allvariableshashref->{'PRODUCTCODE'} = $installer::globals::productcode; 1785 $allvariableshashref->{'UPGRADECODE'} = $installer::globals::upgradecode; 1786 1787 $infoline = "Defined variable PRODUCTCODE: $installer::globals::productcode \n"; 1788 $installer::logger::Lang->print($infoline); 1789 1790 $infoline = "Defined variable UPGRADECODE: $installer::globals::upgradecode \n"; 1791 $installer::logger::Lang->print($infoline); 1792 1793} 1794 1795############################################################### 1796# Setting the product version used in property table and 1797# upgrade table. Saving in global variable $msiproductversion 1798############################################################### 1799 1800sub set_msiproductversion 1801{ 1802 my ( $allvariables ) = @_; 1803 1804 my $productversion = $allvariables->{'PRODUCTVERSION'}; 1805 1806 if (( $productversion =~ /^\s*\d+\s*$/ ) && ( $productversion > 255 )) { $productversion = $productversion%256; } 1807 1808 if ( $productversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) 1809 { 1810 $productversion = $1 . "\." . $2 . $3 . "\." . $installer::globals::buildid; 1811 } 1812 elsif ( $productversion =~ /^\s*(\d+)\.(\d+)\s*$/ ) 1813 { 1814 $productversion = $1 . "\." . $2 . "\." . $installer::globals::buildid; 1815 } 1816 else 1817 { 1818 my $productminor = "00"; 1819 if (( $allvariables->{'PACKAGEVERSION'} ) && ( $allvariables->{'PACKAGEVERSION'} ne "" )) 1820 { 1821 if ( $allvariables->{'PACKAGEVERSION'} =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) { $productminor = $2; } 1822 } 1823 1824 $productversion = $productversion . "\." . $productminor . "\." . $installer::globals::buildid; 1825 } 1826 1827 $installer::globals::msiproductversion = $productversion; 1828 1829 # Setting $installer::globals::msimajorproductversion, to differ between old version in upgrade table 1830 1831 if ( $installer::globals::msiproductversion =~ /^\s*(\d+)\./ ) 1832 { 1833 my $major = $1; 1834 $installer::globals::msimajorproductversion = $major . "\.0\.0"; 1835 } 1836} 1837 1838################################################################################# 1839# Including the msi product version into the bootstrap.ini, Windows only 1840################################################################################# 1841 1842sub put_msiproductversion_into_bootstrapfile 1843{ 1844 my ($filesref) = @_; 1845 1846 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 1847 { 1848 my $onefile = ${$filesref}[$i]; 1849 1850 if ( $onefile->{'gid'} eq "gid_Profile_Version_Ini" ) 1851 { 1852 my $file = installer::files::read_file($onefile->{'sourcepath'}); 1853 1854 for ( my $j = 0; $j <= $#{$file}; $j++ ) 1855 { 1856 ${$file}[$j] =~ s/\<msiproductversion\>/$installer::globals::msiproductversion/; 1857 } 1858 1859 installer::files::save_file($onefile->{'sourcepath'}, $file); 1860 1861 last; 1862 } 1863 } 1864} 1865 1866#################################################################################### 1867# Updating the file Property.idt dynamically 1868# Content: 1869# Property Value 1870#################################################################################### 1871 1872sub update_reglocat_table 1873{ 1874 my ($basedir, $allvariables) = @_; 1875 1876 my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt"; 1877 1878 # Only do something, if this file exists 1879 1880 if ( -f $reglocatfilename ) 1881 { 1882 my $reglocatfile = installer::files::read_file($reglocatfilename); 1883 1884 my $layername = ""; 1885 if ( $allvariables->{'REGISTRYLAYERNAME'} ) 1886 { 1887 $layername = $allvariables->{'REGISTRYLAYERNAME'}; 1888 } 1889 else 1890 { 1891 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ ) 1892 { 1893 if ( ${$reglocatfile}[$i] =~ /\bLAYERNAMETEMPLATE\b/ ) 1894 { 1895 installer::exiter::exit_program("ERROR: Variable \"REGISTRYLAYERNAME\" has to be defined", "update_reglocat_table"); 1896 } 1897 } 1898 } 1899 1900 if ( $layername ne "" ) 1901 { 1902 # Updating the layername in 1903 1904 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ ) 1905 { 1906 ${$reglocatfile}[$i] =~ s/\bLAYERNAMETEMPLATE\b/$layername/; 1907 } 1908 1909 # Saving the file 1910 installer::files::save_file($reglocatfilename ,$reglocatfile); 1911 my $infoline = "Updated idt file: $reglocatfilename\n"; 1912 $installer::logger::Lang->print($infoline); 1913 } 1914 } 1915} 1916 1917 1918 1919#################################################################################### 1920# Updating the file RemoveRe.idt dynamically (RemoveRegistry.idt) 1921# The name of the component has to be replaced. 1922#################################################################################### 1923 1924sub update_removere_table 1925{ 1926 my ($basedir) = @_; 1927 1928 my $removeregistryfilename = $basedir . $installer::globals::separator . "RemoveRe.idt"; 1929 1930 # Only do something, if this file exists 1931 1932 if ( -f $removeregistryfilename ) 1933 { 1934 my $removeregistryfile = installer::files::read_file($removeregistryfilename); 1935 1936 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ ) 1937 { 1938 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ ) 1939 { 1940 ${$removeregistryfile}[$i] =~ s/\bREGISTRYROOTCOMPONENT\b/$installer::globals::registryrootcomponent/; 1941 } 1942 } 1943 1944 # Saving the file 1945 installer::files::save_file($removeregistryfilename ,$removeregistryfile); 1946 my $infoline = "Updated idt file: $removeregistryfilename \n"; 1947 $installer::logger::Lang->print($infoline); 1948 } 1949} 1950 1951########################################################################## 1952# Reading saved mappings in Files.idt and Director.idt. 1953# This is required, if installation sets shall be created, 1954# that can be used for creation of msp files. 1955########################################################################## 1956 1957sub read_saved_mappings 1958{ 1959 installer::logger::include_header_into_logfile("Reading saved mappings from older installation sets:"); 1960 1961 $installer::logger::Lang->add_timestamp("Performance Info: Reading saved mappings start"); 1962 1963 if ( $installer::globals::previous_idt_dir ) 1964 { 1965 my @errorlines = (); 1966 my $errorstring = ""; 1967 my $error_occured = 0; 1968 my $file_error_occured = 0; 1969 my $dir_error = 0; 1970 1971 my $idtdir = $installer::globals::previous_idt_dir; 1972 $idtdir =~ s/\Q$installer::globals::separator\E\s*$//; 1973 1974 # Reading File.idt 1975 1976 my $idtfile = $idtdir . $installer::globals::separator . "File.idt"; 1977 $installer::logger::Global->print("\n"); 1978 $installer::logger::Global->printf("Analyzing file: %s\n", $idtfile); 1979 if ( ! -f $idtfile ) 1980 { 1981 $installer::logger::Global->printf("Warning: File %s does not exist!\n", $idtfile); 1982 } 1983 1984 my $n = 0; 1985 open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings"); 1986 <F>; <F>; <F>; 1987 while (<F>) 1988 { 1989 m/^([^\t]+)\t([^\t]+)\t((.*)\|)?([^\t]*)/; 1990 print "OUT1: \$1: $1, \$2: $2, \$3: $3, \$4: $4, \$5: $5\n"; 1991 next if ("$1" eq "$5") && (!defined($3)); 1992 my $lc1 = lc($1); 1993 1994 if ( exists($installer::globals::savedmapping{"$2/$5"})) 1995 { 1996 if ( ! $file_error_occured ) 1997 { 1998 $errorstring = "\nErrors in $idtfile: \n"; 1999 push(@errorlines, $errorstring); 2000 } 2001 $errorstring = "Duplicate savedmapping{" . "$2/$5}\n"; 2002 push(@errorlines, $errorstring); 2003 $error_occured = 1; 2004 $file_error_occured = 1; 2005 } 2006 2007 if ( exists($installer::globals::savedrevmapping{$lc1})) 2008 { 2009 if ( ! $file_error_occured ) 2010 { 2011 $errorstring = "\nErrors in $idtfile: \n"; 2012 push(@errorlines, $errorstring); 2013 } 2014 $errorstring = "Duplicate savedrevmapping{" . "$lc1}\n"; 2015 push(@errorlines, $errorstring); 2016 $error_occured = 1; 2017 $file_error_occured = 1; 2018 } 2019 2020 my $shortname = $4 || ''; 2021 2022 # Don't reuse illegal 8.3 mappings that we used to generate in 2.0.4 2023 if (index($shortname, '.') > 8 || 2024 (index($shortname, '.') == -1 && length($shortname) > 8)) 2025 { 2026 $shortname = ''; 2027 } 2028 2029 if (( $shortname ne '' ) && ( index($shortname, '~') > 0 ) && ( exists($installer::globals::savedrev83mapping{$shortname}) )) 2030 { 2031 if ( ! $file_error_occured ) 2032 { 2033 $errorstring = "\nErrors in $idtfile: \n"; 2034 push(@errorlines, $errorstring); 2035 } 2036 $errorstring = "Duplicate savedrev83mapping{" . "$shortname}\n"; 2037 push(@errorlines, $errorstring); 2038 $error_occured = 1; 2039 $file_error_occured = 1; 2040 } 2041 2042 $installer::globals::savedmapping{"$2/$5"} = "$1;$shortname"; 2043 $installer::globals::savedrevmapping{lc($1)} = "$2/$5"; 2044 $installer::globals::savedrev83mapping{$shortname} = "$2/$5" if $shortname ne ''; 2045 $n++; 2046 } 2047 2048 close (F); 2049 2050 $installer::logger::Global->printf("Read %s old file table key or 8.3 name mappings from %s\n", 2051 $n, $idtfile); 2052 2053 # Reading Director.idt 2054 2055 $idtfile = $idtdir . $installer::globals::separator . "Director.idt"; 2056 $installer::logger::Global->print("\n"); 2057 $installer::logger::Global->printf("Analyzing file %s\n", $idtfile); 2058 if ( ! -f $idtfile ) 2059 { 2060 $installer::logger::Global->printf("Warning: File %s does not exist!\n", $idtfile); 2061 } 2062 2063 $n = 0; 2064 open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings"); 2065 <F>; <F>; <F>; 2066 while (<F>) 2067 { 2068 m/^([^\t]+)\t([^\t]+)\t(([^~]+~\d.*)\|)?([^\t]*)/; 2069 next if (!defined($3)); 2070 my $lc1 = lc($1); 2071 2072 print "OUT2: \$1: $1, \$2: $2, \$3: $3\n"; 2073 2074 if ( exists($installer::globals::saved83dirmapping{$1}) ) 2075 { 2076 if ( ! $dir_error_occured ) 2077 { 2078 $errorstring = "\nErrors in $idtfile: \n"; 2079 push(@errorlines, $errorstring); 2080 } 2081 $errorstring = "Duplicate saved83dirmapping{" . "$1}\n"; 2082 push(@errorlines, $errorstring); 2083 $error_occured = 1; 2084 $dir_error_occured = 1; 2085 } 2086 2087 $installer::globals::saved83dirmapping{$1} = $4; 2088 $n++; 2089 } 2090 close (F); 2091 2092 $installer::logger::Global->printf("Read %s old directory 8.3 name mappings from %s\n", 2093 $n, $idtfile); 2094 2095 # Analyzing errors 2096 2097 if ( $error_occured ) 2098 { 2099 for my $line (@errorlines) 2100 { 2101 $installer::logger::Info->print($line); 2102 $installer::logger::Global->print($line); 2103 } 2104 installer::exiter::exit_program("ERROR: Duplicate entries in saved mappings!", "read_saved_mappings"); 2105 } 2106 } else { 2107 installer::exiter::exit_program("ERROR: Windows patch shall be prepared, but environment variable PREVIOUS_IDT_DIR is not set!", "read_saved_mappings"); 2108 } 2109 2110 $installer::logger::Lang->add_timestamp("Performance Info: Reading saved mappings end"); 2111} 2112 21131; 2114 2115