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# Calculating a ID with a string using md5 (very fast). 1531################################################################# 1532 1533sub calculate_id 1534{ 1535 my ( $string, $length ) = @_; 1536 1537 my $id = ""; 1538 1539 my $md5 = Digest::MD5->new; 1540 $md5->add($string); 1541 my $digest = lc($md5->hexdigest); 1542 $id = substr($digest, 0, $length); 1543 1544 return $id; 1545} 1546 1547################################################################# 1548# Filling the component hash with the values of the 1549# component file. 1550################################################################# 1551 1552sub fill_component_hash 1553{ 1554 my ($componentfile) = @_; 1555 1556 my %components = (); 1557 1558 for ( my $i = 0; $i <= $#{$componentfile}; $i++ ) 1559 { 1560 my $line = ${$componentfile}[$i]; 1561 1562 if ( $line =~ /^\s*(.*?)\t(.*?)\s*$/ ) 1563 { 1564 my $key = $1; 1565 my $value = $2; 1566 1567 $components{$key} = $value; 1568 } 1569 } 1570 1571 return \%components; 1572} 1573 1574################################################################# 1575# Creating a new component file, if new guids were generated. 1576################################################################# 1577 1578sub create_new_component_file 1579{ 1580 my ($componenthash) = @_; 1581 1582 my @componentfile = (); 1583 1584 my $key; 1585 1586 foreach $key (keys %{$componenthash}) 1587 { 1588 my $value = $componenthash->{$key}; 1589 my $input = "$key\t$value\n"; 1590 push(@componentfile ,$input); 1591 } 1592 1593 return \@componentfile; 1594} 1595 1596################################################################# 1597# Filling real component GUID into the component table. 1598# This works only on Windows 1599################################################################# 1600 1601sub set_uuid_into_component_table 1602{ 1603 my ($idtdirbase, $allvariables) = @_; 1604 1605 my $componenttablename = $idtdirbase . $installer::globals::separator . "Componen.idt"; 1606 1607 my $componenttable = installer::files::read_file($componenttablename); 1608 1609 # For update and patch reasons (small update) the GUID of an existing component must not change! 1610 # The collection of component GUIDs is saved in the directory $installer::globals::idttemplatepath in the file "components.txt" 1611 1612 my $infoline = ""; 1613 my $counter = 0; 1614 # my $componentfile = installer::files::read_file($installer::globals::componentfilename); 1615 # my $componenthash = fill_component_hash($componentfile); 1616 1617 for ( my $i = 3; $i <= $#{$componenttable}; $i++ ) # ignoring the first three lines 1618 { 1619 my $oneline = ${$componenttable}[$i]; 1620 my $componentname = ""; 1621 if ( $oneline =~ /^\s*(\S+?)\t/ ) { $componentname = $1; } 1622 1623 my $uuid = ""; 1624 1625 # if ( $componenthash->{$componentname} ) 1626 # { 1627 # $uuid = $componenthash->{$componentname}; 1628 # } 1629 # else 1630 # { 1631 1632 if ( exists($installer::globals::calculated_component_guids{$componentname})) 1633 { 1634 $uuid = $installer::globals::calculated_component_guids{$componentname}; 1635 } 1636 else 1637 { 1638 # Calculating new GUID with the help of the component name. 1639 my $useooobaseversion = 1; 1640 if ( exists($installer::globals::base_independent_components{$componentname})) { $useooobaseversion = 0; } 1641 my $sourcestring = $componentname; 1642 1643 if ( $useooobaseversion ) 1644 { 1645 if ( ! exists($allvariables->{'OOOBASEVERSION'}) ) { installer::exiter::exit_program("ERROR: Could not find variable \"OOOBASEVERSION\" (required value for GUID creation)!", "set_uuid_into_component_table"); } 1646 $sourcestring = $sourcestring . "_" . $allvariables->{'OOOBASEVERSION'}; 1647 } 1648 $uuid = calculate_guid($sourcestring); 1649 $counter++; 1650 1651 # checking, if there is a conflict with an already created guid 1652 if ( exists($installer::globals::allcalculated_guids{$uuid}) ) { installer::exiter::exit_program("ERROR: \"$uuid\" was already created before!", "set_uuid_into_component_table"); } 1653 $installer::globals::allcalculated_guids{$uuid} = 1; 1654 $installer::globals::calculated_component_guids{$componentname} = $uuid; 1655 1656 # Setting new uuid 1657 # $componenthash->{$componentname} = $uuid; 1658 1659 # Setting flag 1660 # $installer::globals::created_new_component_guid = 1; # this is very important! 1661 } 1662 # } 1663 1664 ${$componenttable}[$i] =~ s/COMPONENTGUID/$uuid/; 1665 } 1666 1667 installer::files::save_file($componenttablename, $componenttable); 1668 1669# if ( $installer::globals::created_new_component_guid ) 1670# { 1671# # create new component file! 1672# $componentfile = create_new_component_file($componenthash); 1673# installer::worker::sort_array($componentfile); 1674# 1675# # To avoid conflict the components file cannot be saved at the same place 1676# # All important data have to be saved in the directory: $installer::globals::infodirectory 1677# my $localcomponentfilename = $installer::globals::componentfilename; 1678# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$localcomponentfilename); 1679# $localcomponentfilename = $installer::globals::infodirectory . $installer::globals::separator . $localcomponentfilename; 1680# installer::files::save_file($localcomponentfilename, $componentfile); 1681# 1682# # installer::files::save_file($installer::globals::componentfilename, $componentfile); # version using new file in solver 1683# 1684# $infoline = "COMPONENTCODES: Created $counter new GUIDs for components ! \n"; 1685# push( @installer::globals::logfileinfo, $infoline); 1686# } 1687# else 1688# { 1689# $infoline = "SUCCESS COMPONENTCODES: All component codes exist! \n"; 1690# push( @installer::globals::logfileinfo, $infoline); 1691# } 1692 1693} 1694 1695######################################################################### 1696# Adding final 64 properties into msi database, if required. 1697# RegLocator : +16 in type column to search in 64 bit registry. 1698# All conditions: "VersionNT" -> "VersionNT64" (several tables). 1699# Already done: "+256" in Attributes column of table "Component". 1700# Still following: Setting "x64" instead of "Intel" in Summary 1701# Information Stream of msi database in "get_template_for_sis". 1702######################################################################### 1703 1704sub prepare_64bit_database 1705{ 1706 my ($basedir, $allvariables) = @_; 1707 1708 my $infoline = ""; 1709 1710 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) 1711 { 1712 # 1. Beginning with table "RegLocat.idt". Adding "16" to the type. 1713 1714 my $reglocatfile = ""; 1715 my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt"; 1716 1717 if ( -f $reglocatfilename ) 1718 { 1719 my $saving_required = 0; 1720 $reglocatfile = installer::files::read_file($reglocatfilename); 1721 1722 for ( my $i = 3; $i <= $#{$reglocatfile}; $i++ ) # ignoring the first three lines 1723 { 1724 my $oneline = ${$reglocatfile}[$i]; 1725 1726 if ( $oneline =~ /^\s*\#/ ) { next; } # this is a comment line 1727 if ( $oneline =~ /^\s*$/ ) { next; } 1728 1729 if ( $oneline =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(\d+)\s*$/ ) 1730 { 1731 # Syntax: Signature_ Root Key Name Type 1732 my $sig = $1; 1733 my $root = $2; 1734 my $key = $3; 1735 my $name = $4; 1736 my $type = $5; 1737 1738 $type = $type + 16; 1739 1740 my $newline = $sig . "\t" . $root . "\t" . $key . "\t" . $name . "\t" . $type . "\n"; 1741 ${$reglocatfile}[$i] = $newline; 1742 1743 $saving_required = 1; 1744 } 1745 } 1746 1747 if ( $saving_required ) 1748 { 1749 # Saving the files 1750 installer::files::save_file($reglocatfilename ,$reglocatfile); 1751 $infoline = "Making idt file 64 bit conform: $reglocatfilename\n"; 1752 push(@installer::globals::logfileinfo, $infoline); 1753 } 1754 } 1755 1756 # 2. Replacing all occurences of "VersionNT" by "VersionNT64" 1757 1758 my @versionnt_files = ("Componen.idt", "InstallE.idt", "InstallU.idt", "LaunchCo.idt"); 1759 1760 foreach my $onefile ( @versionnt_files ) 1761 { 1762 my $fullfilename = $basedir . $installer::globals::separator . $onefile; 1763 1764 if ( -f $fullfilename ) 1765 { 1766 my $saving_required = 0; 1767 $filecontent = installer::files::read_file($fullfilename); 1768 1769 for ( my $i = 3; $i <= $#{$filecontent}; $i++ ) # ignoring the first three lines 1770 { 1771 my $oneline = ${$filecontent}[$i]; 1772 1773 if ( $oneline =~ /\bVersionNT\b/ ) 1774 { 1775 ${$filecontent}[$i] =~ s/\bVersionNT\b/VersionNT64/g; 1776 $saving_required = 1; 1777 } 1778 } 1779 1780 if ( $saving_required ) 1781 { 1782 # Saving the files 1783 installer::files::save_file($fullfilename ,$filecontent); 1784 $infoline = "Making idt file 64 bit conform: $fullfilename\n"; 1785 push(@installer::globals::logfileinfo, $infoline); 1786 } 1787 } 1788 } 1789 } 1790 1791} 1792 1793################################################################# 1794# Include all cab files into the msi database. 1795# This works only on Windows 1796################################################################# 1797 1798sub include_cabs_into_msi 1799{ 1800 my ($installdir) = @_; 1801 1802 installer::logger::include_header_into_logfile("Including cabs into msi database"); 1803 1804 my $from = cwd(); 1805 my $to = $installdir; 1806 1807 chdir($to); 1808 1809 my $infoline = "Changing into directory: $to"; 1810 push( @installer::globals::logfileinfo, $infoline); 1811 1812 my $msidb = "msidb.exe"; # Has to be in the path 1813 my $extraslash = ""; # Has to be set for non-ActiveState perl 1814 1815 my $msifilename = $installer::globals::msidatabasename; 1816 1817 $msifilename = installer::converter::make_path_conform($msifilename); 1818 1819 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.) 1820 $msifilename =~ s/\//\\\\/g; 1821 $extraslash = "\\"; 1822 1823 my $allcabfiles = installer::systemactions::find_file_with_file_extension("cab", $installdir); 1824 1825 for ( my $i = 0; $i <= $#{$allcabfiles}; $i++ ) 1826 { 1827 my $systemcall = $msidb . " -d " . $msifilename . " -a " . ${$allcabfiles}[$i]; 1828 1829 my $returnvalue = system($systemcall); 1830 1831 $infoline = "Systemcall: $systemcall\n"; 1832 push( @installer::globals::logfileinfo, $infoline); 1833 1834 if ($returnvalue) 1835 { 1836 $infoline = "ERROR: Could not execute $systemcall !\n"; 1837 push( @installer::globals::logfileinfo, $infoline); 1838 } 1839 else 1840 { 1841 $infoline = "Success: Executed $systemcall successfully!\n"; 1842 push( @installer::globals::logfileinfo, $infoline); 1843 } 1844 1845 # deleting the cab file 1846 1847 unlink(${$allcabfiles}[$i]); 1848 1849 $infoline = "Deleted cab file: ${$allcabfiles}[$i]\n"; 1850 push( @installer::globals::logfileinfo, $infoline); 1851 } 1852 1853 $infoline = "Changing back into directory: $from"; 1854 push( @installer::globals::logfileinfo, $infoline); 1855 1856 chdir($from); 1857} 1858 1859################################################################# 1860# Executing the created batch file to pack all files. 1861# This works only on Windows 1862################################################################# 1863 1864sub execute_packaging 1865{ 1866 my ($localpackjobref, $loggingdir, $allvariables) = @_; 1867 1868 installer::logger::include_header_into_logfile("Packaging process"); 1869 1870 installer::logger::include_timestamp_into_logfile("Performance Info: Execute packaging start"); 1871 1872 my $infoline = ""; 1873 my $from = cwd(); 1874 my $to = $loggingdir; 1875 1876 chdir($to); 1877 $infoline = "chdir: $to \n"; 1878 push( @installer::globals::logfileinfo, $infoline); 1879 1880 # if the ddf file contains relative pathes, it is necessary to change into the temp directory 1881 if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) 1882 { 1883 $to = $installer::globals::temppath; 1884 chdir($to); 1885 $infoline = "chdir: $to \n"; 1886 push( @installer::globals::logfileinfo, $infoline); 1887 } 1888 1889 # changing the tmp directory, because makecab.exe generates temporary cab files 1890 my $origtemppath = ""; 1891 if ( $ENV{'TMP'} ) { $origtemppath = $ENV{'TMP'}; } 1892 $ENV{'TMP'} = $installer::globals::temppath; # setting TMP to the new unique directory! 1893 1894 my $maxmakecabcalls = 3; 1895 my $allmakecabcalls = $#{$localpackjobref} + 1; 1896 1897 for ( my $i = 0; $i <= $#{$localpackjobref}; $i++ ) 1898 { 1899 my $systemcall = ${$localpackjobref}[$i]; 1900 1901 my $callscounter = $i + 1; 1902 1903 installer::logger::print_message( "... makecab.exe ($callscounter/$allmakecabcalls) ... \n" ); 1904 1905 # my $returnvalue = system($systemcall); 1906 1907 for ( my $n = 1; $n <= $maxmakecabcalls; $n++ ) 1908 { 1909 my @ddfoutput = (); 1910 1911 $infoline = "Systemcall: $systemcall"; 1912 push( @installer::globals::logfileinfo, $infoline); 1913 1914 open (DDF, "$systemcall"); 1915 while (<DDF>) {push(@ddfoutput, $_); } 1916 close (DDF); 1917 1918 my $returnvalue = $?; # $? contains the return value of the systemcall 1919 1920 if ($returnvalue) 1921 { 1922 if ( $n < $maxmakecabcalls ) 1923 { 1924 installer::logger::print_message( "makecab_error (Try $n): Trying again \n" ); 1925 $infoline = "makecab_error (Try $n): $systemcall !"; 1926 } 1927 else 1928 { 1929 installer::logger::print_message( "ERROR (Try $n): Abort packing \n" ); 1930 $infoline = "ERROR (Try $n): $systemcall !"; 1931 } 1932 1933 push( @installer::globals::logfileinfo, $infoline); 1934 # for ( my $j = 0; $j <= $#ddfoutput; $j++ ) { push( @installer::globals::logfileinfo, "$ddfoutput[$j]"); } 1935 1936 for ( my $m = 0; $m <= $#ddfoutput; $m++ ) 1937 { 1938 if ( $ddfoutput[$m] =~ /(ERROR\:.*?)\s*$/ ) 1939 { 1940 $infoline = $1 . "\n"; 1941 if ( $n < $maxmakecabcalls ) { $infoline =~ s/ERROR\:/makecab_error\:/i; } 1942 installer::logger::print_message( $infoline ); 1943 push( @installer::globals::logfileinfo, $infoline); 1944 } 1945 } 1946 1947 if ( $n == $maxmakecabcalls ) { installer::exiter::exit_program("ERROR: \"$systemcall\"!", "execute_packaging"); } 1948 } 1949 else 1950 { 1951 # installer::logger::print_message( "Success (Try $n): \"$systemcall\"\n" ); 1952 $infoline = "Success (Try $n): $systemcall"; 1953 push( @installer::globals::logfileinfo, $infoline); 1954 last; 1955 } 1956 } 1957 } 1958 1959 installer::logger::include_timestamp_into_logfile("Performance Info: Execute packaging end"); 1960 1961 # setting back to the original tmp directory 1962 $ENV{'TMP'} = $origtemppath; 1963 1964 chdir($from); 1965 $infoline = "chdir: $from \n"; 1966 push( @installer::globals::logfileinfo, $infoline); 1967} 1968 1969############################################################### 1970# Setting the global variables ProductCode and the UpgradeCode 1971############################################################### 1972 1973sub set_global_code_variables 1974{ 1975 my ( $languagesref, $languagestringref, $allvariableshashref, $alloldproperties ) = @_; 1976 1977 # In the msi template directory a files "codes.txt" has to exist, in which the ProductCode 1978 # and the UpgradeCode for the product are defined. 1979 # The name "codes.txt" can be overwritten in Product definition with CODEFILENAME . 1980 # Default $installer::globals::codefilename is defined in parameter.pm. 1981 1982 if ( $allvariableshashref->{'CODEFILENAME'} ) 1983 { 1984 $installer::globals::codefilename = $installer::globals::idttemplatepath . $installer::globals::separator . $allvariableshashref->{'CODEFILENAME'}; 1985 installer::files::check_file($installer::globals::codefilename); 1986 } 1987 1988 my $infoline = "Using Codes file: $installer::globals::codefilename \n"; 1989 push( @installer::globals::logfileinfo, $infoline); 1990 1991 my $codefile = installer::files::read_file($installer::globals::codefilename); 1992 1993 my $isopensource = 0; 1994 if ( $allvariableshashref->{'OPENSOURCE'} ) { $isopensource = $allvariableshashref->{'OPENSOURCE'}; } 1995 1996 my $onelanguage = ""; 1997 1998 if ( $#{$languagesref} > 0 ) # more than one language 1999 { 2000 if (( $installer::globals::added_english ) && ( $#{$languagesref} == 1 )) # only multilingual because of added English 2001 { 2002 $onelanguage = ${$languagesref}[1]; # setting the first language, that is not english 2003 } 2004 else 2005 { 2006 if (( ${$languagesref}[1] =~ /jp/ ) || 2007 ( ${$languagesref}[1] =~ /ko/ ) || 2008 ( ${$languagesref}[1] =~ /zh/ )) 2009 { 2010 $onelanguage = "multiasia"; 2011 } 2012 else 2013 { 2014 $onelanguage = "multiwestern"; 2015 } 2016 } 2017 } 2018 else # only one language 2019 { 2020 $onelanguage = ${$languagesref}[0]; 2021 } 2022 2023 # ProductCode must not change, if Windows patches shall be applied 2024 if ( $installer::globals::updatedatabase ) 2025 { 2026 $installer::globals::productcode = $alloldproperties->{'ProductCode'}; 2027 } 2028 elsif ( $installer::globals::prepare_winpatch ) 2029 { 2030 # ProductCode has to be specified in each language 2031 my $searchstring = "PRODUCTCODE"; 2032 my $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile); 2033 $installer::globals::productcode = installer::windows::idtglobal::get_code_from_code_block($codeblock, $onelanguage); 2034 } else { 2035 my $guidref = get_guid_list(1, 1); # only one GUID shall be generated 2036 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces 2037 $installer::globals::productcode = "\{" . ${$guidref}[0] . "\}"; 2038 } 2039 2040 if ( $installer::globals::patch ) # patch upgrade codes are defined in soffice.lst 2041 { 2042 if ( $allvariableshashref->{'PATCHUPGRADECODE'} ) { $installer::globals::upgradecode = $allvariableshashref->{'PATCHUPGRADECODE'}; } 2043 else { installer::exiter::exit_program("ERROR: PATCHUPGRADECODE not defined in list file!", "set_global_code_variables"); } 2044 } 2045 else 2046 { 2047 # UpgradeCode can take english as default, if not defined in specified language 2048 2049 $searchstring = "UPGRADECODE"; # searching in the codes.txt file 2050 $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile); 2051 $installer::globals::upgradecode = installer::windows::idtglobal::get_language_string_from_language_block($codeblock, $onelanguage, ""); 2052 } 2053 2054 # 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"); } 2055 if ( $installer::globals::upgradecode eq "" ) { installer::exiter::exit_program("ERROR: UpgradeCode not defined in $installer::globals::codefilename !", "set_global_code_variables"); } 2056 2057 $infoline = "Setting ProductCode to: $installer::globals::productcode \n"; 2058 push( @installer::globals::logfileinfo, $infoline); 2059 $infoline = "Setting UpgradeCode to: $installer::globals::upgradecode \n"; 2060 push( @installer::globals::logfileinfo, $infoline); 2061 2062 # Adding both variables into the variables array 2063 2064 $allvariableshashref->{'PRODUCTCODE'} = $installer::globals::productcode; 2065 $allvariableshashref->{'UPGRADECODE'} = $installer::globals::upgradecode; 2066 2067 $infoline = "Defined variable PRODUCTCODE: $installer::globals::productcode \n"; 2068 push( @installer::globals::logfileinfo, $infoline); 2069 2070 $infoline = "Defined variable UPGRADECODE: $installer::globals::upgradecode \n"; 2071 push( @installer::globals::logfileinfo, $infoline); 2072 2073} 2074 2075############################################################### 2076# Setting the product version used in property table and 2077# upgrade table. Saving in global variable $msiproductversion 2078############################################################### 2079 2080sub set_msiproductversion 2081{ 2082 my ( $allvariables ) = @_; 2083 2084 my $productversion = $allvariables->{'PRODUCTVERSION'}; 2085 2086 if (( $productversion =~ /^\s*\d+\s*$/ ) && ( $productversion > 255 )) { $productversion = $productversion%256; } 2087 2088 if ( $productversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) 2089 { 2090 $productversion = $1 . "\." . $2 . $3 . "\." . $installer::globals::buildid; 2091 } 2092 elsif ( $productversion =~ /^\s*(\d+)\.(\d+)\s*$/ ) 2093 { 2094 $productversion = $1 . "\." . $2 . "\." . $installer::globals::buildid; 2095 } 2096 else 2097 { 2098 my $productminor = "00"; 2099 if (( $allvariables->{'PACKAGEVERSION'} ) && ( $allvariables->{'PACKAGEVERSION'} ne "" )) 2100 { 2101 if ( $allvariables->{'PACKAGEVERSION'} =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) { $productminor = $2; } 2102 } 2103 2104 $productversion = $productversion . "\." . $productminor . "\." . $installer::globals::buildid; 2105 } 2106 2107 $installer::globals::msiproductversion = $productversion; 2108 2109 # Setting $installer::globals::msimajorproductversion, to differ between old version in upgrade table 2110 2111 if ( $installer::globals::msiproductversion =~ /^\s*(\d+)\./ ) 2112 { 2113 my $major = $1; 2114 $installer::globals::msimajorproductversion = $major . "\.0\.0"; 2115 } 2116} 2117 2118################################################################################# 2119# Including the msi product version into the bootstrap.ini, Windows only 2120################################################################################# 2121 2122sub put_msiproductversion_into_bootstrapfile 2123{ 2124 my ($filesref) = @_; 2125 2126 for ( my $i = 0; $i <= $#{$filesref}; $i++ ) 2127 { 2128 my $onefile = ${$filesref}[$i]; 2129 2130 if ( $onefile->{'gid'} eq "gid_Profile_Version_Ini" ) 2131 { 2132 my $file = installer::files::read_file($onefile->{'sourcepath'}); 2133 2134 for ( my $j = 0; $j <= $#{$file}; $j++ ) 2135 { 2136 ${$file}[$j] =~ s/\<msiproductversion\>/$installer::globals::msiproductversion/; 2137 } 2138 2139 installer::files::save_file($onefile->{'sourcepath'}, $file); 2140 2141 last; 2142 } 2143 } 2144} 2145 2146#################################################################################### 2147# Updating the file Property.idt dynamically 2148# Content: 2149# Property Value 2150#################################################################################### 2151 2152sub update_reglocat_table 2153{ 2154 my ($basedir, $allvariables) = @_; 2155 2156 my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt"; 2157 2158 # Only do something, if this file exists 2159 2160 if ( -f $reglocatfilename ) 2161 { 2162 my $reglocatfile = installer::files::read_file($reglocatfilename); 2163 2164 my $layername = ""; 2165 if ( $allvariables->{'REGISTRYLAYERNAME'} ) 2166 { 2167 $layername = $allvariables->{'REGISTRYLAYERNAME'}; 2168 } 2169 else 2170 { 2171 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ ) 2172 { 2173 if ( ${$reglocatfile}[$i] =~ /\bLAYERNAMETEMPLATE\b/ ) 2174 { 2175 installer::exiter::exit_program("ERROR: Variable \"REGISTRYLAYERNAME\" has to be defined", "update_reglocat_table"); 2176 } 2177 } 2178 } 2179 2180 if ( $layername ne "" ) 2181 { 2182 # Updating the layername in 2183 2184 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ ) 2185 { 2186 ${$reglocatfile}[$i] =~ s/\bLAYERNAMETEMPLATE\b/$layername/; 2187 } 2188 2189 # Saving the file 2190 installer::files::save_file($reglocatfilename ,$reglocatfile); 2191 my $infoline = "Updated idt file: $reglocatfilename\n"; 2192 push(@installer::globals::logfileinfo, $infoline); 2193 } 2194 } 2195} 2196 2197 2198 2199#################################################################################### 2200# Updating the file RemoveRe.idt dynamically (RemoveRegistry.idt) 2201# The name of the component has to be replaced. 2202#################################################################################### 2203 2204sub update_removere_table 2205{ 2206 my ($basedir) = @_; 2207 2208 my $removeregistryfilename = $basedir . $installer::globals::separator . "RemoveRe.idt"; 2209 2210 # Only do something, if this file exists 2211 2212 if ( -f $removeregistryfilename ) 2213 { 2214 my $removeregistryfile = installer::files::read_file($removeregistryfilename); 2215 2216 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ ) 2217 { 2218 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ ) 2219 { 2220 ${$removeregistryfile}[$i] =~ s/\bREGISTRYROOTCOMPONENT\b/$installer::globals::registryrootcomponent/; 2221 } 2222 } 2223 2224 # Saving the file 2225 installer::files::save_file($removeregistryfilename ,$removeregistryfile); 2226 my $infoline = "Updated idt file: $removeregistryfilename \n"; 2227 push(@installer::globals::logfileinfo, $infoline); 2228 } 2229} 2230 2231########################################################################## 2232# Reading saved mappings in Files.idt and Director.idt. 2233# This is required, if installation sets shall be created, 2234# that can be used for creation of msp files. 2235########################################################################## 2236 2237sub read_saved_mappings 2238{ 2239 installer::logger::include_header_into_logfile("Reading saved mappings from older installation sets:"); 2240 2241 installer::logger::include_timestamp_into_logfile("Performance Info: Reading saved mappings start"); 2242 2243 if ( $installer::globals::previous_idt_dir ) 2244 { 2245 my @errorlines = (); 2246 my $errorstring = ""; 2247 my $error_occured = 0; 2248 my $file_error_occured = 0; 2249 my $dir_error = 0; 2250 2251 my $idtdir = $installer::globals::previous_idt_dir; 2252 $idtdir =~ s/\Q$installer::globals::separator\E\s*$//; 2253 2254 # Reading File.idt 2255 2256 my $idtfile = $idtdir . $installer::globals::separator . "File.idt"; 2257 push( @installer::globals::globallogfileinfo, "\nAnalyzing file: $idtfile\n" ); 2258 if ( ! -f $idtfile ) { push( @installer::globals::globallogfileinfo, "Warning: File $idtfile does not exist!\n" ); } 2259 2260 my $n = 0; 2261 open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings"); 2262 <F>; <F>; <F>; 2263 while (<F>) 2264 { 2265 m/^([^\t]+)\t([^\t]+)\t((.*)\|)?([^\t]*)/; 2266 print "OUT1: \$1: $1, \$2: $2, \$3: $3, \$4: $4, \$5: $5\n"; 2267 next if ("$1" eq "$5") && (!defined($3)); 2268 my $lc1 = lc($1); 2269 2270 if ( exists($installer::globals::savedmapping{"$2/$5"})) 2271 { 2272 if ( ! $file_error_occured ) 2273 { 2274 $errorstring = "\nErrors in $idtfile: \n"; 2275 push(@errorlines, $errorstring); 2276 } 2277 $errorstring = "Duplicate savedmapping{" . "$2/$5}\n"; 2278 push(@errorlines, $errorstring); 2279 $error_occured = 1; 2280 $file_error_occured = 1; 2281 } 2282 2283 if ( exists($installer::globals::savedrevmapping{$lc1})) 2284 { 2285 if ( ! $file_error_occured ) 2286 { 2287 $errorstring = "\nErrors in $idtfile: \n"; 2288 push(@errorlines, $errorstring); 2289 } 2290 $errorstring = "Duplicate savedrevmapping{" . "$lc1}\n"; 2291 push(@errorlines, $errorstring); 2292 $error_occured = 1; 2293 $file_error_occured = 1; 2294 } 2295 2296 my $shortname = $4 || ''; 2297 2298 # Don't reuse illegal 8.3 mappings that we used to generate in 2.0.4 2299 if (index($shortname, '.') > 8 || 2300 (index($shortname, '.') == -1 && length($shortname) > 8)) 2301 { 2302 $shortname = ''; 2303 } 2304 2305 if (( $shortname ne '' ) && ( index($shortname, '~') > 0 ) && ( exists($installer::globals::savedrev83mapping{$shortname}) )) 2306 { 2307 if ( ! $file_error_occured ) 2308 { 2309 $errorstring = "\nErrors in $idtfile: \n"; 2310 push(@errorlines, $errorstring); 2311 } 2312 $errorstring = "Duplicate savedrev83mapping{" . "$shortname}\n"; 2313 push(@errorlines, $errorstring); 2314 $error_occured = 1; 2315 $file_error_occured = 1; 2316 } 2317 2318 $installer::globals::savedmapping{"$2/$5"} = "$1;$shortname"; 2319 $installer::globals::savedrevmapping{lc($1)} = "$2/$5"; 2320 $installer::globals::savedrev83mapping{$shortname} = "$2/$5" if $shortname ne ''; 2321 $n++; 2322 } 2323 2324 close (F); 2325 2326 push( @installer::globals::globallogfileinfo, "Read $n old file table key or 8.3 name mappings from $idtfile\n" ); 2327 2328 # Reading Director.idt 2329 2330 $idtfile = $idtdir . $installer::globals::separator . "Director.idt"; 2331 push( @installer::globals::globallogfileinfo, "\nAnalyzing file $idtfile\n" ); 2332 if ( ! -f $idtfile ) { push( @installer::globals::globallogfileinfo, "Warning: File $idtfile does not exist!\n" ); } 2333 2334 $n = 0; 2335 open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings"); 2336 <F>; <F>; <F>; 2337 while (<F>) 2338 { 2339 m/^([^\t]+)\t([^\t]+)\t(([^~]+~\d.*)\|)?([^\t]*)/; 2340 next if (!defined($3)); 2341 my $lc1 = lc($1); 2342 2343 print "OUT2: \$1: $1, \$2: $2, \$3: $3\n"; 2344 2345 if ( exists($installer::globals::saved83dirmapping{$1}) ) 2346 { 2347 if ( ! $dir_error_occured ) 2348 { 2349 $errorstring = "\nErrors in $idtfile: \n"; 2350 push(@errorlines, $errorstring); 2351 } 2352 $errorstring = "Duplicate saved83dirmapping{" . "$1}\n"; 2353 push(@errorlines, $errorstring); 2354 $error_occured = 1; 2355 $dir_error_occured = 1; 2356 } 2357 2358 $installer::globals::saved83dirmapping{$1} = $4; 2359 $n++; 2360 } 2361 close (F); 2362 2363 push( @installer::globals::globallogfileinfo, "Read $n old directory 8.3 name mappings from $idtfile\n" ); 2364 2365 # Analyzing errors 2366 2367 if ( $error_occured ) 2368 { 2369 for ( my $i = 0; $i <= $#errorlines; $i++ ) 2370 { 2371 print "$errorlines[$i]"; 2372 push( @installer::globals::globallogfileinfo, "$errorlines[$i]"); 2373 } 2374 installer::exiter::exit_program("ERROR: Duplicate entries in saved mappings!", "read_saved_mappings"); 2375 } 2376 } else { 2377 # push( @installer::globals::globallogfileinfo, "WARNING: Windows patch shall be prepared, but PREVIOUS_IDT_DIR is not set!\n" ); 2378 installer::exiter::exit_program("ERROR: Windows patch shall be prepared, but environment variable PREVIOUS_IDT_DIR is not set!", "read_saved_mappings"); 2379 } 2380 2381 installer::logger::include_timestamp_into_logfile("Performance Info: Reading saved mappings end"); 2382} 2383 23841; 2385 2386