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