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