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