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