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