2 # This file is part of the LibreOffice project.
4 # This Source Code Form is subject to the terms of the Mozilla Public
5 # License, v. 2.0. If a copy of the MPL was not distributed with this
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 # This file incorporates work covered by the following license notice:
10 # Licensed to the Apache Software Foundation (ASF) under one or more
11 # contributor license agreements. See the NOTICE file distributed
12 # with this work for additional information regarding copyright
13 # ownership. The ASF licenses this file to you under the Apache
14 # License, Version 2.0 (the "License"); you may not use this file
15 # except in compliance with the License. You may obtain a copy of
16 # the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package installer
::windows
::msiglobal
;
23 use installer
::converter
;
24 use installer
::exiter
;
26 use installer
::globals
;
27 use installer
::logger
;
28 use installer
::pathanalyzer
;
29 use installer
::remover
;
30 use installer
::scriptitems
;
31 use installer
::systemactions
;
32 use installer
::worker
;
33 use installer
::windows
::idtglobal
;
34 use installer
::windows
::language
;
36 ###########################################################################
37 # Generating the header of the ddf file.
38 # The usage of ddf files is needed, because makecab.exe can only include
39 # one sourcefile into a cab file
40 ###########################################################################
42 sub write_ddf_file_header
44 my ($ddffileref, $cabinetfile, $installdir) = @_;
48 $oneline = ".Set CabinetName1=" . $cabinetfile . "\n";
49 push(@
{$ddffileref} ,$oneline);
50 $oneline = ".Set ReservePerCabinetSize=128\n"; # This reserves space for a digital signature.
51 push(@
{$ddffileref} ,$oneline);
52 $oneline = ".Set MaxDiskSize=2147483648\n"; # This allows the .cab file to get a size of 2 GB.
53 push(@
{$ddffileref} ,$oneline);
54 $oneline = ".Set CompressionType=LZX\n";
55 push(@
{$ddffileref} ,$oneline);
56 $oneline = ".Set Compress=ON\n";
57 push(@
{$ddffileref} ,$oneline);
58 # The window size for LZX compression
59 # CompressionMemory=15 | 16 | ... | 21
60 # Reference: http://msdn.microsoft.com/en-us/library/bb417343.aspx
61 $oneline = ".Set CompressionMemory=$installer::globals::cabfilecompressionlevel\n";
62 push(@
{$ddffileref} ,$oneline);
63 $oneline = ".Set Cabinet=ON\n";
64 push(@
{$ddffileref} ,$oneline);
65 $oneline = ".Set DiskDirectoryTemplate=" . $installdir . "\n";
66 push(@
{$ddffileref} ,$oneline);
69 ##########################################################################
70 # Lines in ddf files must not contain more than 256 characters
71 ##########################################################################
75 my ( $ddffile, $ddffilename ) = @_;
82 for ( my $i = 0; $i <= $#{$ddffile}; $i++ )
84 my $oneline = ${$ddffile}[$i];
86 $linelength = length($oneline);
89 if ( $linelength > 256 )
91 installer
::exiter
::exit_program
("ERROR \"$ddffilename\" line $linenumber: Lines in ddf files must not contain more than 256 characters!", "check_ddf_file");
94 if ( $linelength > $maxlength )
96 $maxlength = $linelength;
97 $maxline = $linenumber;
101 my $infoline = "Check of ddf file \"$ddffilename\": Maximum length \"$maxlength\" in line \"$maxline\" (allowed line length: 256 characters)\n";
102 push(@installer::globals
::logfileinfo
, $infoline);
105 ##########################################################################
106 # Lines in ddf files must not be longer than 256 characters.
107 # Therefore it can be useful to use relative paths. Then it is
108 # necessary to change into temp directory before calling
110 ##########################################################################
112 sub make_relative_ddf_path
114 my ( $sourcepath ) = @_;
116 my $windowstemppath = $installer::globals
::temppath
;
118 if ( $^O
=~ /cygwin/i )
120 $windowstemppath = $installer::globals
::cyg_temppath
;
123 $sourcepath =~ s/\Q$windowstemppath\E//;
124 $sourcepath =~ s/^[\\\/]//;
129 ##########################################################################
130 # Returning the order of the sequences in the files array.
131 ##########################################################################
133 sub get_sequenceorder
139 for ( my $i = 0; $i <= $#{$filesref}; $i++ )
141 my $onefile = ${$filesref}[$i];
142 if ( ! $onefile->{'assignedsequencenumber'} ) { installer
::exiter
::exit_program
("ERROR: No sequence number assigned to $onefile->{'gid'} ($onefile->{'uniquename'})!", "get_sequenceorder"); }
143 $order{$onefile->{'assignedsequencenumber'}} = $i;
149 ##########################################################################
150 # Generation the list, in which the source of the files is connected
151 # with the cabinet destination file. Because more than one file needs
152 # to be included into a cab file, this has to be done via ddf files.
153 ##########################################################################
155 sub generate_cab_file_list
157 my ($filesref, $installdir, $ddfdir, $allvariables) = @_;
159 my @cabfilelist = ();
161 installer
::logger
::include_header_into_logfile
("Generating ddf files");
163 installer
::logger
::include_timestamp_into_logfile
("Performance Info: ddf file generation start");
165 if ( $^O
=~ /cygwin/i ) { installer
::worker
::generate_cygwin_paths
($filesref); }
167 if (( $installer::globals
::fix_number_of_cab_files
) && ( $installer::globals
::updatedatabase
))
169 my $sequenceorder = get_sequenceorder
($filesref);
173 while ( ( exists($sequenceorder->{$counter}) ) || ( exists($installer::globals
::allmergemodulefilesequences
{$counter}) ) ) # Taking care of files from merge modules
175 # if ( exists($installer::globals::allmergemodulefilesequences{$counter}) )
177 # # Skipping this sequence, it is not included in $filesref, because it is assigned to a file from a merge module.\n";
182 my $onefile = ${$filesref}[$sequenceorder->{$counter}];
185 my $cabinetfile = $onefile->{'cabinet'};
186 my $sourcepath = $onefile->{'sourcepath'};
187 if ( $^O
=~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
188 my $uniquename = $onefile->{'uniquename'};
192 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
193 if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
195 # to avoid lines with more than 256 characters, it can be useful to use relative paths
196 $sourcepath = make_relative_ddf_path
($sourcepath);
200 write_ddf_file_header
(\
@ddffile, $cabinetfile, $installdir);
202 my $ddfline = "\"" . $sourcepath . "\" \"" . $uniquename . "\"\n";
203 if ( $doinclude ) { push(@ddffile, $ddfline); }
206 if ( ${$filesref}[$sequenceorder->{$counter}] ) { $nextfile = ${$filesref}[$sequenceorder->{$counter}]; }
208 my $nextcabinetfile = "";
210 if ( $nextfile->{'cabinet'} ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
212 while ( $nextcabinetfile eq $cabinetfile )
214 $sourcepath = $nextfile->{'sourcepath'};
215 if ( $^O
=~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; }
216 # to avoid lines with more than 256 characters, it can be useful to use relative paths
217 $sourcepath = make_relative_ddf_path
($sourcepath);
218 $uniquename = $nextfile->{'uniquename'};
219 my $localdoinclude = 1;
220 my $nextfilestyles = "";
221 if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; }
222 if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; }
223 $ddfline = "\"" . $sourcepath . "\" \"" . $uniquename . "\"\n";
224 if ( $localdoinclude ) { push(@ddffile, $ddfline); }
227 $nextcabinetfile = "_lastfile_";
228 if (( exists($sequenceorder->{$counter}) ) && ( ${$filesref}[$sequenceorder->{$counter}] ))
230 $nextfile = ${$filesref}[$sequenceorder->{$counter}];
231 $nextcabinetfile = $nextfile->{'cabinet'};
235 # creating the DDF file
237 my $ddffilename = $cabinetfile;
238 $ddffilename =~ s/.cab/.ddf/;
239 $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//;
240 $ddffilename = $ddfdir . $installer::globals
::separator
. $ddffilename;
242 installer
::files
::save_file
($ddffilename ,\
@ddffile);
243 my $infoline = "Created ddf file: $ddffilename\n";
244 push(@installer::globals
::logfileinfo
, $infoline);
246 # lines in ddf files must not be longer than 256 characters
247 check_ddf_file
(\
@ddffile, $ddffilename);
249 # Writing the makecab system call
251 my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
252 if ( $installer::globals
::isunix
)
254 $oneline = "$ENV{'WORKDIR_FOR_BUILD'}/LinkTarget/Executable/makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
257 push(@cabfilelist, $oneline);
259 # collecting all ddf files
260 push(@installer::globals
::allddffiles
, $ddffilename);
263 elsif ( $installer::globals
::fix_number_of_cab_files
)
265 for ( my $i = 0; $i <= $#{$filesref}; $i++ )
267 my $onefile = ${$filesref}[$i];
268 my $cabinetfile = $onefile->{'cabinet'};
269 my $sourcepath = $onefile->{'sourcepath'};
270 if ( $^O
=~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
271 my $uniquename = $onefile->{'uniquename'};
275 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
276 if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
279 # to avoid lines with more than 256 characters, it can be useful to use relative paths
280 $sourcepath = make_relative_ddf_path
($sourcepath);
282 # all files with the same cabinetfile are directly behind each other in the files collector
286 write_ddf_file_header
(\
@ddffile, $cabinetfile, $installdir);
288 my $ddfline = "\"" . $sourcepath . "\" \"" . $uniquename . "\"\n";
289 if ( $doinclude ) { push(@ddffile, $ddfline); }
291 my $nextfile = ${$filesref}[$i+1];
292 my $nextcabinetfile = "";
294 if ( $nextfile->{'cabinet'} ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
296 while ( $nextcabinetfile eq $cabinetfile )
298 $sourcepath = $nextfile->{'sourcepath'};
299 if ( $^O
=~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; }
300 # to avoid lines with more than 256 characters, it can be useful to use relative paths
301 $sourcepath = make_relative_ddf_path
($sourcepath);
302 $uniquename = $nextfile->{'uniquename'};
303 my $localdoinclude = 1;
304 my $nextfilestyles = "";
305 if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; }
306 if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; }
307 $ddfline = "\"" . $sourcepath . "\" \"" . $uniquename . "\"\n";
308 if ( $localdoinclude ) { push(@ddffile, $ddfline); }
309 $i++; # increasing the counter!
310 $nextfile = ${$filesref}[$i+1];
311 if ( $nextfile ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
312 else { $nextcabinetfile = "_lastfile_"; }
315 # creating the DDF file
317 my $ddffilename = $cabinetfile;
318 $ddffilename =~ s/.cab/.ddf/;
319 $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//;
320 $ddffilename = $ddfdir . $installer::globals
::separator
. $ddffilename;
322 installer
::files
::save_file
($ddffilename ,\
@ddffile);
323 my $infoline = "Created ddf file: $ddffilename\n";
324 push(@installer::globals
::logfileinfo
, $infoline);
326 # lines in ddf files must not be longer than 256 characters
327 check_ddf_file
(\
@ddffile, $ddffilename);
329 # Writing the makecab system call
331 my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
332 if ( $installer::globals
::isunix
)
334 $oneline = "$ENV{'WORKDIR_FOR_BUILD'}/LinkTarget/Executable/makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
337 push(@cabfilelist, $oneline);
339 # collecting all ddf files
340 push(@installer::globals
::allddffiles
, $ddffilename);
345 installer
::exiter
::exit_program
("ERROR: No cab file specification in globals.pm !", "generate_cab_file_list");
348 installer
::logger
::include_timestamp_into_logfile
("Performance Info: ddf file generation end");
350 return \
@cabfilelist; # contains all system calls for packaging process
353 ########################################################################
354 # For update and patch reasons the pack order needs to be saved.
355 # The pack order is saved in the ddf files; the names and locations
356 # of the ddf files are saved in @installer::globals::allddffiles.
357 # The outputfile "packorder.txt" can be saved in
358 # $installer::globals::infodirectory .
359 ########################################################################
363 installer
::logger
::include_header_into_logfile
("Saving pack order");
365 installer
::logger
::include_timestamp_into_logfile
("Performance Info: saving pack order start");
367 my $packorderfilename = "packorder.txt";
368 $packorderfilename = $installer::globals
::infodirectory
. $installer::globals
::separator
. $packorderfilename;
372 my $headerline = "\# Syntax\: Filetable_Sequence Cabinetfilename Physical_FileName Unique_FileName\n\n";
373 push(@packorder, $headerline);
375 for ( my $i = 0; $i <= $#installer::globals
::allddffiles
; $i++ )
377 my $ddffilename = $installer::globals
::allddffiles
[$i];
378 my $ddffile = installer
::files
::read_file
($ddffilename);
379 my $cabinetfile = "";
381 for ( my $j = 0; $j <= $#{$ddffile}; $j++ )
383 my $oneline = ${$ddffile}[$j];
385 # Getting the Cabinet file name
387 if ( $oneline =~ /^\s*\.Set\s+CabinetName.*\=(.*?)\s*$/ ) { $cabinetfile = $1; }
388 if ( $oneline =~ /^\s*\.Set\s+/ ) { next; }
390 if ( $oneline =~ /^\s*\"(.*?)\"\s+\"(.*?)\"\s*$/ )
393 my $uniquefilename = $2;
395 installer
::pathanalyzer
::make_absolute_filename_to_relative_filename
(\
$sourcefile);
397 # Using the hash created in create_files_table for performance reasons to get the sequence number
398 my $filesequence = "";
399 if ( exists($installer::globals
::uniquefilenamesequence
{$uniquefilename}) ) { $filesequence = $installer::globals
::uniquefilenamesequence
{$uniquefilename}; }
400 else { installer
::exiter
::exit_program
("ERROR: No sequence number value for $uniquefilename !", "save_packorder"); }
402 my $line = $filesequence . "\t" . $cabinetfile . "\t" . $sourcefile . "\t" . $uniquefilename . "\n";
403 push(@packorder, $line);
408 installer
::files
::save_file
($packorderfilename ,\
@packorder);
410 installer
::logger
::include_timestamp_into_logfile
("Performance Info: saving pack order end");
413 #################################################################
414 # Returning the name of the msi database
415 #################################################################
417 sub get_msidatabasename
419 my ($allvariableshashref, $language) = @_;
421 my $databasename = $allvariableshashref->{'PRODUCTNAME'} . $allvariableshashref->{'PRODUCTVERSION'};
422 $databasename = lc($databasename);
423 $databasename =~ s/\.//g;
424 $databasename =~ s/\-//g;
425 $databasename =~ s/\s//g;
427 # possibility to overwrite the name with variable DATABASENAME
428 if ( $allvariableshashref->{'DATABASENAME'} )
430 $databasename = $allvariableshashref->{'DATABASENAME'};
435 if (!($language eq ""))
437 $databasename .= "_$language";
441 $databasename .= ".msi";
443 return $databasename;
446 #################################################################
447 # Creating the msi database
448 # This works only on Windows
449 #################################################################
451 sub create_msi_database
453 my ($idtdirbase ,$msifilename) = @_;
455 # -f : path containing the idt files
456 # -d : msi database, including path
457 # -c : create database
458 # -i : include the following tables ("*" includes all available tables)
460 my $msidb = "msidb.exe"; # Has to be in the path
461 if ( $installer::globals
::isunix
)
463 $msidb = "$ENV{'WORKDIR_FOR_BUILD'}/LinkTarget/Executable/msidb.exe";
465 my $extraslash = ""; # Has to be set for non-ActiveState perl
467 installer
::logger
::include_header_into_logfile
("Creating msi database");
469 $idtdirbase = installer
::converter
::make_path_conform
($idtdirbase);
471 $msifilename = installer
::converter
::make_path_conform
($msifilename);
473 if ( $^O
=~ /cygwin/i ) {
474 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
475 $idtdirbase =~ s/\//\\\\/g
;
476 $msifilename =~ s/\//\\\\/g
;
479 if ( $^O
=~ /linux/i ) {
482 my $systemcall = $msidb . " -f " . $idtdirbase . " -d " . $msifilename . " -c " . "-i " . $extraslash . "*";
484 my $returnvalue = system($systemcall);
486 my $infoline = "Systemcall: $systemcall\n";
487 push( @installer::globals
::logfileinfo
, $infoline);
491 $infoline = "ERROR: Could not execute $msidb!\n";
492 push( @installer::globals
::logfileinfo
, $infoline);
496 $infoline = "Success: Executed $msidb successfully!\n";
497 push( @installer::globals
::logfileinfo
, $infoline);
501 #################################################################
502 # Returning the msi version for the Summary Information Stream
503 #################################################################
505 sub get_msiversion_for_sis
507 my $msiversion = "200";
511 #################################################################
512 # Returning the word count for the Summary Information Stream
513 #################################################################
515 sub get_wordcount_for_sis
521 #################################################################
522 # Returning the template for the Summary Information Stream
523 #################################################################
525 sub get_template_for_sis
527 my ( $language, $allvariables ) = @_;
529 my $windowslanguage = installer
::windows
::language
::get_windows_language
($language);
531 my $architecture = "Intel";
533 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) { $architecture = "x64"; }
535 my $value = "\"" . $architecture . ";" . $windowslanguage; # adding the Windows language
537 $value = $value . "\""; # adding ending '"'
542 #################################################################
543 # Returning the PackageCode for the Summary Information Stream
544 #################################################################
546 sub get_packagecode_for_sis
548 # always generating a new package code for each package
550 my $guidref = get_guid_list
(1, 1); # only one GUID shall be generated
552 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces
554 my $guid = "\{" . ${$guidref}[0] . "\}";
556 my $infoline = "PackageCode: $guid\n";
557 push( @installer::globals
::logfileinfo
, $infoline);
562 #################################################################
563 # Returning the author for the Summary Information Stream
564 #################################################################
566 sub get_author_for_sis
568 my $author = $installer::globals
::longmanufacturer
;
570 $author = "\"" . $author . "\"";
575 #################################################################
576 # Returning the subject for the Summary Information Stream
577 #################################################################
579 sub get_subject_for_sis
581 my ( $allvariableshashref ) = @_;
583 my $subject = $allvariableshashref->{'PRODUCTNAME'} . " " . $allvariableshashref->{'PRODUCTVERSION'};
585 $subject = "\"" . $subject . "\"";
590 ######################################################################
591 # Returning the security for the Summary Information Stream
592 ######################################################################
594 sub get_security_for_sis
600 #################################################################
601 # Writing the Summary information stream into the msi database
602 # This works only on Windows
603 #################################################################
605 sub write_summary_into_msi_database
607 my ($msifilename, $language, $languagefile, $allvariableshashref) = @_;
609 # -g : required msi version
613 installer
::logger
::include_header_into_logfile
("Writing summary information stream");
615 my $msiinfo = "msiinfo.exe"; # Has to be in the path
616 if ( $installer::globals
::isunix
)
618 $msiinfo = "$ENV{'WORKDIR_FOR_BUILD'}/LinkTarget/Executable/msiinfo.exe";
621 my $msiversion = get_msiversion_for_sis
();
622 my $codepage = 0; # PID_CODEPAGE summary property in a signed short, therefore it is impossible to set 65001 here.
623 my $template = get_template_for_sis
($language, $allvariableshashref);
624 my $guid = get_packagecode_for_sis
();
625 my $title = "\"Installation database\"";
626 my $author = get_author_for_sis
();
627 my $subject = get_subject_for_sis
($allvariableshashref);
628 my $comment = "\"" . $allvariableshashref->{'PRODUCTNAME'} ."\"";
629 my $keywords = "\"Install,MSI\"";
630 my $appname = "\"Windows Installer\"";
631 my $security = get_security_for_sis
();
632 my $wordcount = get_wordcount_for_sis
();
634 $msifilename = installer
::converter
::make_path_conform
($msifilename);
636 my $systemcall = $msiinfo . " " . $msifilename . " -g " . $msiversion . " -c " . $codepage
637 . " -p " . $template . " -v " . $guid . " -t " . $title . " -a " . $author
638 . " -j " . $subject . " -o " . $comment . " -k " . $keywords . " -n " . $appname
639 . " -u " . $security . " -w " . $wordcount;
641 my $returnvalue = system($systemcall);
643 my $infoline = "Systemcall: $systemcall\n";
644 push( @installer::globals
::logfileinfo
, $infoline);
648 $infoline = "ERROR: Could not execute $systemcall (return $returnvalue)\n";
649 push( @installer::globals
::logfileinfo
, $infoline);
653 $infoline = "Success: Executed $msiinfo successfully!\n";
654 push( @installer::globals
::logfileinfo
, $infoline);
658 #########################################################################
659 # For more than one language in the installation set:
660 # Use one database and create Transformations for all other languages
661 #########################################################################
663 sub create_transforms
665 my ($languagesarray, $defaultlanguage, $installdir, $allvariableshashref) = @_;
667 installer
::logger
::include_header_into_logfile
("Creating Transforms");
669 my $cscript = "cscript.exe"; # Has to be in the path
670 my $msitran = "msitran.exe"; # Has to be in the path
671 my $msidb = "msidb.exe"; # Has to be in the path
672 if ( $installer::globals
::isunix
)
674 $infoline = "ERROR: We cannot create transformations yet (we cannot use cscript.exe when cross-compiling)\n";
675 push( @installer::globals
::logfileinfo
, $infoline);
677 my $wilangid = $ENV{WINDOWS_SDK_WILANGID
};
681 my $templatevalue = "1033";
683 $installdir = installer
::converter
::make_path_conform
($installdir);
685 # Syntax for creating a transformation
686 # msitran.exe -g <baseDB> <referenceDB> <transformfile> [<errorhandling>}
688 my $basedbname = get_msidatabasename
($allvariableshashref, $defaultlanguage);
689 $basedbname = $installdir . $installer::globals
::separator
. $basedbname;
691 my $errorhandling = "f"; # Suppress "change codepage" error
693 # Iterating over all files
695 foreach ( @
{$languagesarray} )
697 my $onelanguage = $_;
699 if ( $onelanguage eq $defaultlanguage ) { next; }
701 my $referencedbname = get_msidatabasename
($allvariableshashref, $onelanguage);
702 $referencedbname = $installdir . $installer::globals
::separator
. $referencedbname;
704 my $windowslanguage = installer
::windows
::language
::get_windows_language
($onelanguage);
705 my $transformfile = $installdir . $installer::globals
::separator
. $windowslanguage;
707 my $systemcall = $msitran . " " . " -g " . $basedbname . " " . $referencedbname . " " . $transformfile . " " . $errorhandling;
709 my $returnvalue = system($systemcall);
711 my $infoline = "Systemcall: $systemcall\n";
712 push( @installer::globals
::logfileinfo
, $infoline);
714 # Problem: msitran.exe in version 4.0 always returns "1", even if no failure occurred.
715 # Therefore it has to be checked, if this is version 4.0. If yes, if the mst file
716 # exists and if it is larger than 0 bytes. If this is true, then no error occurred.
717 # File Version of msitran.exe: 4.0.6000.16384 has checksum: "b66190a70145a57773ec769e16777b29".
718 # Same for msitran.exe from wntmsci12: "aa25d3445b94ffde8ef0c1efb77a56b8"
722 $infoline = "WARNING: Returnvalue of $msitran is not 0. Checking version of $msitran!\n";
723 push( @installer::globals
::logfileinfo
, $infoline);
725 open(FILE
, "<$installer::globals::msitranpath") or die "ERROR: Can't open $installer::globals::msitranpath for creating file hash";
727 my $digest = Digest
::MD5
->new->addfile(*FILE
)->hexdigest;
730 my @problemchecksums = ("b66190a70145a57773ec769e16777b29", "aa25d3445b94ffde8ef0c1efb77a56b8", "748206e54fc93efe6a1aaa9d491f3ad1");
731 my $isproblemchecksum = 0;
733 foreach my $problemchecksum ( @problemchecksums )
735 $infoline = "Checksum of problematic MsiTran.exe: $problemchecksum\n";
736 push( @installer::globals
::logfileinfo
, $infoline);
737 $infoline = "Checksum of used MsiTran.exe: $digest\n";
738 push( @installer::globals
::logfileinfo
, $infoline);
739 if ( $digest eq $problemchecksum ) { $isproblemchecksum = 1; }
742 if ( $isproblemchecksum )
744 # Check existence of mst
745 if ( -f
$transformfile )
747 $infoline = "File $transformfile exists.\n";
748 push( @installer::globals
::logfileinfo
, $infoline);
749 my $filesize = ( -s
$transformfile );
750 $infoline = "Size of $transformfile: $filesize\n";
751 push( @installer::globals
::logfileinfo
, $infoline);
755 $infoline = "Info: Returnvalue $returnvalue of $msitran is no problem :-) .\n";
756 push( @installer::globals
::logfileinfo
, $infoline);
757 $returnvalue = 0; # reset the error
761 $infoline = "Filesize indicates that an error occurred.\n";
762 push( @installer::globals
::logfileinfo
, $infoline);
767 $infoline = "File $transformfile does not exist -> An error occurred.\n";
768 push( @installer::globals
::logfileinfo
, $infoline);
773 $infoline = "This is not a problematic version of msitran.exe. Therefore the error is not caused by problematic msitran.exe.\n";
774 push( @installer::globals
::logfileinfo
, $infoline);
780 $infoline = "ERROR: Could not execute $msitran!\n";
781 push( @installer::globals
::logfileinfo
, $infoline);
785 $infoline = "Success: Executed $msitran successfully!\n";
786 push( @installer::globals
::logfileinfo
, $infoline);
789 # The reference database can be deleted
791 my $result = unlink($referencedbname);
792 # $result contains the number of deleted files
796 $infoline = "ERROR: Could not remove file $$referencedbname !\n";
797 push( @installer::globals
::logfileinfo
, $infoline);
798 installer
::exiter
::exit_program
($infoline, "create_transforms");
802 $systemcall = $msidb . " " . " -d " . $basedbname . " -r " . $windowslanguage;
804 # fdo#46181 - zh-HK and zh-MO should have fallen back to zh-TW not to zh-CN
805 # we need to hack zh-HK and zh-MO LCIDs directly into the MSI
806 if($windowslanguage eq '1028')
809 $systemcall = $msidb . " " . " -d " . $basedbname . " -r " . 3076;
812 $systemcall = $msidb . " " . " -d " . $basedbname . " -r " . 5124;
814 $templatevalue = $templatevalue . "," . 3076 . "," . 5124;
818 unlink($transformfile);
820 $infoline = "Systemcall: $systemcall\n";
821 push( @installer::globals
::logfileinfo
, $infoline);
823 if ( $windowslanguage ne '1033')
825 $templatevalue = $templatevalue . "," . $windowslanguage;
829 $systemcall = "TEMP=$ENV{'TMPDIR'} $cscript \"$wilangid\" $basedbname Package $templatevalue";
831 $returnvalue = system($systemcall);
833 $infoline = "Systemcall: $systemcall\n";
834 push( @installer::globals
::logfileinfo
, $infoline);
838 $infoline = "ERROR: $returnvalue from $systemcall\n";
839 push( @installer::globals
::logfileinfo
, $infoline);
843 $infoline = "Success: Executed WiLangId.vbs successfully!\n";
844 push( @installer::globals
::logfileinfo
, $infoline);
848 #########################################################################
849 # The default language msi database does not need to contain
850 # the language in the database name. Therefore the file
851 # is renamed. Example: "openofficeorg20_01.msi" to "openofficeorg20.msi"
852 #########################################################################
854 sub rename_msi_database_in_installset
856 my ($defaultlanguage, $installdir, $allvariableshashref) = @_;
858 installer
::logger
::include_header_into_logfile
("Renaming msi database");
860 my $olddatabasename = get_msidatabasename
($allvariableshashref, $defaultlanguage);
861 $olddatabasename = $installdir . $installer::globals
::separator
. $olddatabasename;
863 my $newdatabasename = get_msidatabasename
($allvariableshashref);
865 $installer::globals
::shortmsidatabasename
= $newdatabasename;
867 $newdatabasename = $installdir . $installer::globals
::separator
. $newdatabasename;
869 installer
::systemactions
::rename_one_file
($olddatabasename, $newdatabasename);
871 $installer::globals
::msidatabasename
= $newdatabasename;
874 #################################################################
875 # Copying MergeModules for the Windows installer into the
876 # installation set. The list of MergeModules is located
877 # in %installer::globals::copy_msm_files
878 #################################################################
880 sub copy_merge_modules_into_installset
882 my ($installdir) = @_;
884 installer
::logger
::include_header_into_logfile
("Copying Merge files into installation set");
887 foreach $cabfile ( keys %installer::globals
::copy_msm_files
)
889 my $sourcefile = $installer::globals
::copy_msm_files
{$cabfile};
890 my $destfile = $installdir . $installer::globals
::separator
. $cabfile;
892 installer
::systemactions
::copy_one_file
($sourcefile, $destfile);
896 #################################################################
897 # Getting a list of GUID using uuidgen.exe.
898 # This works only on Windows
899 #################################################################
903 my ($number, $log) = @_;
905 if ( $log ) { installer
::logger
::include_header_into_logfile
("Generating $number GUID"); }
907 my $uuidgen = $ENV{'UUIDGEN'}; # Has to be in the path
909 # "-c" for uppercase output
911 my $systemcall = "$uuidgen -n$number |";
912 if ( $installer::globals
::isunix
)
914 # -n is not present in the non-windows uuidgen
915 $systemcall = "for I in `seq 1 $number` ; do uuidgen ; done |";
917 open (UUIDGEN
, "$systemcall" ) or die("uuidgen is missing.");
918 my @uuidlist = <UUIDGEN
>;
921 my $infoline = "Systemcall: $systemcall\n";
922 if ( $log ) { push( @installer::globals
::logfileinfo
, $infoline); }
924 my $comparenumber = $#uuidlist + 1;
926 if ( $comparenumber == $number )
928 $infoline = "Success: Executed $uuidgen successfully!\n";
929 if ( $log ) { push( @installer::globals
::logfileinfo
, $infoline); }
933 $infoline = "ERROR: Could not execute $uuidgen successfully!\n";
934 if ( $log ) { push( @installer::globals
::logfileinfo
, $infoline); }
937 # uppercase, no longer "-c", because this is only supported in uuidgen.exe v.1.01
938 for ( my $i = 0; $i <= $#uuidlist; $i++ ) { $uuidlist[$i] = uc($uuidlist[$i]); }
943 #################################################################
944 # Calculating a GUID with a string using md5.
945 #################################################################
953 my $md5 = Digest
::MD5
->new;
955 my $digest = $md5->hexdigest;
956 $digest = uc($digest);
958 my ($first, $second, $third, $fourth, $fifth) = unpack ('A8 A4 A4 A4 A12', $digest);
959 $guid = "$first-$second-$third-$fourth-$fifth";
964 #################################################################
965 # Calculating a ID with a string using md5 (very fast).
966 #################################################################
970 my ( $string, $length ) = @_;
974 my $md5 = Digest
::MD5
->new;
976 my $digest = lc($md5->hexdigest);
977 $id = substr($digest, 0, $length);
982 #################################################################
983 # Filling real component GUID into the component table.
984 # This works only on Windows
985 #################################################################
987 sub set_uuid_into_component_table
989 my ($idtdirbase, $allvariables) = @_;
991 my $componenttablename = $idtdirbase . $installer::globals
::separator
. "Componen.idt";
993 my $componenttable = installer
::files
::read_file
($componenttablename);
995 # For update and patch reasons (small update) the GUID of an existing component must not change!
996 # The collection of component GUIDs is saved in the directory $installer::globals::idttemplatepath in the file "components.txt"
1001 for ( my $i = 3; $i <= $#{$componenttable}; $i++ ) # ignoring the first three lines
1003 my $oneline = ${$componenttable}[$i];
1004 my $componentname = "";
1005 if ( $oneline =~ /^\s*(\S+?)\t/ ) { $componentname = $1; }
1009 if ( exists($installer::globals
::calculated_component_guids
{$componentname}))
1011 $uuid = $installer::globals
::calculated_component_guids
{$componentname};
1015 # Calculating new GUID with the help of the component name.
1017 if ( ! exists($allvariables->{'PRODUCTVERSION'}) ) { installer
::exiter
::exit_program
("ERROR: Could not find variable \"PRODUCTVERSION\" (required value for GUID creation)!", "set_uuid_into_component_table"); }
1018 my $sourcestring = $componentname . "_" . $allvariables->{'PRODUCTVERSION'};
1019 $uuid = calculate_guid
($sourcestring);
1022 # checking, if there is a conflict with an already created guid
1023 if ( exists($installer::globals
::allcalculated_guids
{$uuid}) ) { installer
::exiter
::exit_program
("ERROR: \"$uuid\" was already created before!", "set_uuid_into_component_table"); }
1024 $installer::globals
::allcalculated_guids
{$uuid} = 1;
1025 $installer::globals
::calculated_component_guids
{$componentname} = $uuid;
1028 ${$componenttable}[$i] =~ s/COMPONENTGUID/$uuid/;
1031 installer
::files
::save_file
($componenttablename, $componenttable);
1034 #########################################################################
1035 # Adding final 64 properties into msi database, if required.
1036 # RegLocator : +16 in type column to search in 64 bit registry.
1037 # All conditions: "VersionNT" -> "VersionNT64" (several tables).
1038 # Already done: "+256" in Attributes column of table "Component".
1039 # Still following: Setting "x64" instead of "Intel" in Summary
1040 # Information Stream of msi database in "get_template_for_sis".
1041 #########################################################################
1043 sub prepare_64bit_database
1045 my ($basedir, $allvariables) = @_;
1049 if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 ))
1051 # 1. Beginning with table "RegLocat.idt". Adding "16" to the type.
1053 my $reglocatfile = "";
1054 my $reglocatfilename = $basedir . $installer::globals
::separator
. "RegLocat.idt";
1056 if ( -f
$reglocatfilename )
1058 my $saving_required = 0;
1059 $reglocatfile = installer
::files
::read_file
($reglocatfilename);
1061 for ( my $i = 3; $i <= $#{$reglocatfile}; $i++ ) # ignoring the first three lines
1063 my $oneline = ${$reglocatfile}[$i];
1065 if ( $oneline =~ /^\s*\#/ ) { next; } # this is a comment line
1066 if ( $oneline =~ /^\s*$/ ) { next; }
1068 if ( $oneline =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(\d+)\s*$/ )
1070 # Syntax: Signature_ Root Key Name Type
1079 my $newline = $sig . "\t" . $root . "\t" . $key . "\t" . $name . "\t" . $type . "\n";
1080 ${$reglocatfile}[$i] = $newline;
1082 $saving_required = 1;
1086 if ( $saving_required )
1089 installer
::files
::save_file
($reglocatfilename ,$reglocatfile);
1090 $infoline = "Making idt file 64 bit conform: $reglocatfilename\n";
1091 push(@installer::globals
::logfileinfo
, $infoline);
1095 # 2. Replacing all occurrences of "VersionNT" by "VersionNT64"
1097 my @versionnt_files = ("Componen.idt", "InstallE.idt", "InstallU.idt", "LaunchCo.idt");
1099 foreach my $onefile ( @versionnt_files )
1101 my $fullfilename = $basedir . $installer::globals
::separator
. $onefile;
1103 if ( -f
$fullfilename )
1105 my $saving_required = 0;
1106 $filecontent = installer
::files
::read_file
($fullfilename);
1108 for ( my $i = 3; $i <= $#{$filecontent}; $i++ ) # ignoring the first three lines
1110 my $oneline = ${$filecontent}[$i];
1112 if ( $oneline =~ /\bVersionNT\b/ )
1114 ${$filecontent}[$i] =~ s/\bVersionNT\b/VersionNT64/g;
1115 $saving_required = 1;
1119 if ( $saving_required )
1122 installer
::files
::save_file
($fullfilename ,$filecontent);
1123 $infoline = "Making idt file 64 bit conform: $fullfilename\n";
1124 push(@installer::globals
::logfileinfo
, $infoline);
1132 #################################################################
1133 # Include all cab files into the msi database.
1134 # This works only on Windows
1135 #################################################################
1137 sub include_cabs_into_msi
1139 my ($installdir) = @_;
1141 installer
::logger
::include_header_into_logfile
("Including cabs into msi database");
1144 my $to = $installdir;
1148 my $infoline = "Changing into directory: $to";
1149 push( @installer::globals
::logfileinfo
, $infoline);
1151 my $msidb = "msidb.exe"; # Has to be in the path
1152 if ( $installer::globals
::isunix
)
1154 $msidb = "$ENV{'WORKDIR_FOR_BUILD'}/LinkTarget/Executable/msidb.exe";
1156 my $extraslash = ""; # Has to be set for non-ActiveState perl
1158 my $msifilename = $installer::globals
::msidatabasename
;
1160 $msifilename = installer
::converter
::make_path_conform
($msifilename);
1162 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
1163 $msifilename =~ s/\//\\\\/g
;
1166 my $allcabfiles = installer
::systemactions
::find_file_with_file_extension
("cab", $installdir);
1168 for ( my $i = 0; $i <= $#{$allcabfiles}; $i++ )
1170 my $systemcall = $msidb . " -d " . $msifilename . " -a " . ${$allcabfiles}[$i];
1172 my $returnvalue = system($systemcall);
1174 $infoline = "Systemcall: $systemcall\n";
1175 push( @installer::globals
::logfileinfo
, $infoline);
1179 $infoline = "ERROR: Could not execute $systemcall !\n";
1180 push( @installer::globals
::logfileinfo
, $infoline);
1184 $infoline = "Success: Executed $systemcall successfully!\n";
1185 push( @installer::globals
::logfileinfo
, $infoline);
1188 # deleting the cab file
1190 unlink(${$allcabfiles}[$i]);
1192 $infoline = "Deleted cab file: ${$allcabfiles}[$i]\n";
1193 push( @installer::globals
::logfileinfo
, $infoline);
1196 $infoline = "Changing back into directory: $from";
1197 push( @installer::globals
::logfileinfo
, $infoline);
1202 #################################################################
1203 # Executing the created batch file to pack all files.
1204 # This works only on Windows
1205 #################################################################
1207 sub execute_packaging
1209 my ($localpackjobref, $loggingdir, $allvariables) = @_;
1211 installer
::logger
::include_header_into_logfile
("Packaging process");
1213 installer
::logger
::include_timestamp_into_logfile
("Performance Info: Execute packaging start");
1217 my $to = $loggingdir;
1220 $infoline = "chdir: $to \n";
1221 push( @installer::globals
::logfileinfo
, $infoline);
1223 # the ddf file contains relative paths, it is necessary to change into the temp directory
1224 $to = $installer::globals
::temppath
;
1226 $infoline = "chdir: $to \n";
1227 push( @installer::globals
::logfileinfo
, $infoline);
1229 my $maxmakecabcalls = 3;
1230 my $allmakecabcalls = $#{$localpackjobref} + 1;
1232 for ( my $i = 0; $i <= $#{$localpackjobref}; $i++ )
1234 my $systemcall = ${$localpackjobref}[$i];
1236 my $callscounter = $i + 1;
1238 installer
::logger
::print_message
( "... makecab.exe ($callscounter/$allmakecabcalls) ... \n" );
1240 for ( my $n = 1; $n <= $maxmakecabcalls; $n++ )
1244 $infoline = "Systemcall: $systemcall";
1245 push( @installer::globals
::logfileinfo
, $infoline);
1247 open (DDF
, "$systemcall");
1248 while (<DDF
>) {push(@ddfoutput, $_); }
1251 my $returnvalue = $?
; # $? contains the return value of the systemcall
1255 if ( $n < $maxmakecabcalls )
1257 installer
::logger
::print_message
( "makecab_error (Try $n): Trying again \n" );
1258 $infoline = "makecab_error (Try $n): $systemcall !";
1262 installer
::logger
::print_message
( "ERROR (Try $n): Abort packing \n" );
1263 $infoline = "ERROR (Try $n): $systemcall !";
1266 push( @installer::globals
::logfileinfo
, $infoline);
1268 for ( my $m = 0; $m <= $#ddfoutput; $m++ )
1270 if ( $ddfoutput[$m] =~ /(ERROR\:.*?)\s*$/ )
1272 $infoline = $1 . "\n";
1273 if ( $n < $maxmakecabcalls ) { $infoline =~ s/ERROR\:/makecab_error\:/i; }
1274 installer
::logger
::print_message
( $infoline );
1275 push( @installer::globals
::logfileinfo
, $infoline);
1279 if ( $n == $maxmakecabcalls ) { installer
::exiter
::exit_program
("ERROR: \"$systemcall\"!", "execute_packaging"); }
1283 $infoline = "Success (Try $n): $systemcall";
1284 push( @installer::globals
::logfileinfo
, $infoline);
1290 installer
::logger
::include_timestamp_into_logfile
("Performance Info: Execute packaging end");
1293 $infoline = "chdir: $from \n";
1294 push( @installer::globals
::logfileinfo
, $infoline);
1297 ###############################################################
1298 # Setting the global variables ProductCode and the UpgradeCode
1299 ###############################################################
1301 sub set_global_code_variables
1303 my ( $languagesref, $languagestringref, $allvariableshashref, $alloldproperties ) = @_;
1305 # In the msi template directory a files "codes.txt" has to exist, in which the ProductCode
1306 # and the UpgradeCode for the product are defined.
1307 # The name "codes.txt" can be overwritten in Product definition with CODEFILENAME .
1308 # Default $installer::globals::codefilename is defined in parameter.pm.
1310 if ( $allvariableshashref->{'CODEFILENAME'} )
1312 $installer::globals
::codefilename
= $installer::globals
::idttemplatepath
. $installer::globals
::separator
. $allvariableshashref->{'CODEFILENAME'};
1313 installer
::files
::check_file
($installer::globals
::codefilename
);
1316 my $infoline = "Using Codes file: $installer::globals::codefilename \n";
1317 push( @installer::globals
::logfileinfo
, $infoline);
1319 my $codefile = installer
::files
::read_file
($installer::globals
::codefilename
);
1321 my $onelanguage = "";
1323 if ( $#{$languagesref} > 0 ) # more than one language
1325 if (( $installer::globals
::added_english
) && ( $#{$languagesref} == 1 )) # only multilingual because of added English
1327 $onelanguage = ${$languagesref}[1]; # setting the first language, that is not english
1331 if (( ${$languagesref}[1] =~ /jp/ ) ||
1332 ( ${$languagesref}[1] =~ /ko/ ) ||
1333 ( ${$languagesref}[1] =~ /zh/ ))
1335 $onelanguage = "multiasia";
1339 $onelanguage = "multiwestern";
1343 else # only one language
1345 $onelanguage = ${$languagesref}[0];
1348 # ProductCode must not change, if Windows patches shall be applied
1349 if ( $installer::globals
::updatedatabase
)
1351 $installer::globals
::productcode
= $alloldproperties->{'ProductCode'};
1353 elsif ( $installer::globals
::prepare_winpatch
)
1355 # ProductCode has to be specified in each language
1356 my $searchstring = "PRODUCTCODE";
1357 my $codeblock = installer
::windows
::idtglobal
::get_language_block_from_language_file
($searchstring, $codefile);
1358 $installer::globals
::productcode
= installer
::windows
::idtglobal
::get_code_from_code_block
($codeblock, $onelanguage);
1360 my $guidref = get_guid_list
(1, 1); # only one GUID shall be generated
1361 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces
1362 $installer::globals
::productcode
= "\{" . ${$guidref}[0] . "\}";
1365 # UpgradeCode can take english as default, if not defined in specified language
1367 $searchstring = "UPGRADECODE"; # searching in the codes.txt file
1368 $codeblock = installer
::windows
::idtglobal
::get_language_block_from_language_file
($searchstring, $codefile);
1369 $installer::globals
::upgradecode
= installer
::windows
::idtglobal
::get_language_string_from_language_block
($codeblock, $onelanguage, "");
1371 if ( $installer::globals
::upgradecode
eq "" ) { installer
::exiter
::exit_program
("ERROR: UpgradeCode not defined in $installer::globals::codefilename !", "set_global_code_variables"); }
1373 $infoline = "Setting ProductCode to: $installer::globals::productcode \n";
1374 push( @installer::globals
::logfileinfo
, $infoline);
1375 $infoline = "Setting UpgradeCode to: $installer::globals::upgradecode \n";
1376 push( @installer::globals
::logfileinfo
, $infoline);
1378 # Adding both variables into the variables array
1380 $allvariableshashref->{'PRODUCTCODE'} = $installer::globals
::productcode
;
1381 $allvariableshashref->{'UPGRADECODE'} = $installer::globals
::upgradecode
;
1383 $infoline = "Defined variable PRODUCTCODE: $installer::globals::productcode \n";
1384 push( @installer::globals
::logfileinfo
, $infoline);
1386 $infoline = "Defined variable UPGRADECODE: $installer::globals::upgradecode \n";
1387 push( @installer::globals
::logfileinfo
, $infoline);
1391 ###############################################################
1392 # Setting the product version used in property table and
1393 # upgrade table. Saving in global variable $msiproductversion
1394 ###############################################################
1396 sub set_msiproductversion
1398 my ( $allvariables ) = @_;
1400 my $productversion = $allvariables->{'PACKAGEVERSION'};
1402 if ( $productversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ )
1404 $productversion = $1 . "\." . $2 . "\." . $3 . "\." . $installer::globals
::buildid
;
1407 $installer::globals
::msiproductversion
= $productversion;
1409 # Setting $installer::globals::msimajorproductversion, to differ between old version in upgrade table
1411 if ( $installer::globals
::msiproductversion
=~ /^\s*(\d+)\./ )
1414 $installer::globals
::msimajorproductversion
= $major . "\.0\.0";
1418 #################################################################################
1419 # Including the msi product version into the bootstrap.ini, Windows only
1420 #################################################################################
1422 sub put_msiproductversion_into_bootstrapfile
1424 my ($filesref) = @_;
1426 for ( my $i = 0; $i <= $#{$filesref}; $i++ )
1428 my $onefile = ${$filesref}[$i];
1430 if ( $onefile->{'gid'} eq "gid_Brand_Profile_Version_Ini" )
1432 my $file = installer
::files
::read_file
($onefile->{'sourcepath'});
1434 for ( my $j = 0; $j <= $#{$file}; $j++ )
1436 ${$file}[$j] =~ s/\<msiproductversion\>/$installer::globals::msiproductversion/;
1439 installer
::files
::save_file
($onefile->{'sourcepath'}, $file);
1446 ####################################################################################
1447 # Updating the file Property.idt dynamically
1450 ####################################################################################
1452 sub update_reglocat_table
1454 my ($basedir, $allvariables) = @_;
1456 my $reglocatfilename = $basedir . $installer::globals
::separator
. "RegLocat.idt";
1458 # Only do something, if this file exists
1460 if ( -f
$reglocatfilename )
1462 my $reglocatfile = installer
::files
::read_file
($reglocatfilename);
1465 if ( $allvariables->{'REGISTRYLAYERNAME'} )
1467 $layername = $allvariables->{'REGISTRYLAYERNAME'};
1471 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ )
1473 if ( ${$reglocatfile}[$i] =~ /\bLAYERNAMETEMPLATE\b/ )
1475 installer
::exiter
::exit_program
("ERROR: Variable \"REGISTRYLAYERNAME\" has to be defined", "update_reglocat_table");
1480 if ( $layername ne "" )
1482 # Updating the layername in
1484 for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ )
1486 ${$reglocatfile}[$i] =~ s/\bLAYERNAMETEMPLATE\b/$layername/;
1490 installer
::files
::save_file
($reglocatfilename ,$reglocatfile);
1491 my $infoline = "Updated idt file: $reglocatfilename\n";
1492 push(@installer::globals
::logfileinfo
, $infoline);
1499 ####################################################################################
1500 # Updating the file RemoveRe.idt dynamically (RemoveRegistry.idt)
1501 # The name of the component has to be replaced.
1502 ####################################################################################
1504 sub update_removere_table
1508 my $removeregistryfilename = $basedir . $installer::globals
::separator
. "RemoveRe.idt";
1510 # Only do something, if this file exists
1512 if ( -f
$removeregistryfilename )
1514 my $removeregistryfile = installer
::files
::read_file
($removeregistryfilename);
1516 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ )
1518 for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ )
1520 ${$removeregistryfile}[$i] =~ s/\bREGISTRYROOTCOMPONENT\b/$installer::globals::registryrootcomponent/;
1525 installer
::files
::save_file
($removeregistryfilename ,$removeregistryfile);
1526 my $infoline = "Updated idt file: $removeregistryfilename \n";
1527 push(@installer::globals
::logfileinfo
, $infoline);
1531 ##########################################################################
1532 # Reading saved mappings in Files.idt and Director.idt.
1533 # This is required, if installation sets shall be created,
1534 # that can be used for creation of msp files.
1535 ##########################################################################
1537 sub read_saved_mappings
1539 installer
::logger
::include_header_into_logfile
("Reading saved mappings from older installation sets:");
1541 installer
::logger
::include_timestamp_into_logfile
("Performance Info: Reading saved mappings start");
1543 if ( $installer::globals
::previous_idt_dir
)
1545 my @errorlines = ();
1546 my $errorstring = "";
1547 my $error_occurred = 0;
1548 my $file_error_occurred = 0;
1549 my $dir_error_occurred = 0;
1551 my $idtdir = $installer::globals
::previous_idt_dir
;
1552 $idtdir =~ s/\Q$installer::globals::separator\E\s*$//;
1556 my $idtfile = $idtdir . $installer::globals
::separator
. "File.idt";
1557 push( @installer::globals
::globallogfileinfo
, "\nAnalyzing file: $idtfile\n" );
1558 if ( ! -f
$idtfile ) { push( @installer::globals
::globallogfileinfo
, "Warning: File $idtfile does not exist!\n" ); }
1561 open (F
, "<$idtfile") || installer
::exiter
::exit_program
("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings");
1565 m/^([^\t]+)\t([^\t]+)\t((.*)\|)?([^\t]*)/;
1566 print "OUT1: \$1: $1, \$2: $2, \$3: $3, \$4: $4, \$5: $5\n";
1567 next if ("$1" eq "$5") && (!defined($3));
1570 if ( exists($installer::globals
::savedmapping
{"$2/$5"}))
1572 if ( ! $file_error_occurred )
1574 $errorstring = "\nErrors in $idtfile: \n";
1575 push(@errorlines, $errorstring);
1577 $errorstring = "Duplicate savedmapping{" . "$2/$5}\n";
1578 push(@errorlines, $errorstring);
1579 $error_occurred = 1;
1580 $file_error_occurred = 1;
1583 if ( exists($installer::globals
::savedrevmapping
{$lc1}))
1585 if ( ! $file_error_occurred )
1587 $errorstring = "\nErrors in $idtfile: \n";
1588 push(@errorlines, $errorstring);
1590 $errorstring = "Duplicate savedrevmapping{" . "$lc1}\n";
1591 push(@errorlines, $errorstring);
1592 $error_occurred = 1;
1593 $file_error_occurred = 1;
1596 my $shortname = $4 || '';
1598 # Don't reuse illegal 8.3 mappings that we used to generate in 2.0.4
1599 if (index($shortname, '.') > 8 ||
1600 (index($shortname, '.') == -1 && length($shortname) > 8))
1605 if (( $shortname ne '' ) && ( index($shortname, '~') > 0 ) && ( exists($installer::globals
::savedrev83mapping
{$shortname}) ))
1607 if ( ! $file_error_occurred )
1609 $errorstring = "\nErrors in $idtfile: \n";
1610 push(@errorlines, $errorstring);
1612 $errorstring = "Duplicate savedrev83mapping{" . "$shortname}\n";
1613 push(@errorlines, $errorstring);
1614 $error_occurred = 1;
1615 $file_error_occurred = 1;
1618 $installer::globals
::savedmapping
{"$2/$5"} = "$1;$shortname";
1619 $installer::globals
::savedrevmapping
{lc($1)} = "$2/$5";
1620 $installer::globals
::savedrev83mapping
{$shortname} = "$2/$5" if $shortname ne '';
1626 push( @installer::globals
::globallogfileinfo
, "Read $n old file table key or 8.3 name mappings from $idtfile\n" );
1628 # Reading Director.idt
1630 $idtfile = $idtdir . $installer::globals
::separator
. "Director.idt";
1631 push( @installer::globals
::globallogfileinfo
, "\nAnalyzing file $idtfile\n" );
1632 if ( ! -f
$idtfile ) { push( @installer::globals
::globallogfileinfo
, "Warning: File $idtfile does not exist!\n" ); }
1635 open (F
, "<$idtfile") || installer
::exiter
::exit_program
("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings");
1639 m/^([^\t]+)\t([^\t]+)\t(([^~]+~\d.*)\|)?([^\t]*)/;
1640 next if (!defined($3));
1643 print "OUT2: \$1: $1, \$2: $2, \$3: $3\n";
1645 if ( exists($installer::globals
::saved83dirmapping
{$1}) )
1647 if ( ! $dir_error_occurred )
1649 $errorstring = "\nErrors in $idtfile: \n";
1650 push(@errorlines, $errorstring);
1652 $errorstring = "Duplicate saved83dirmapping{" . "$1}\n";
1653 push(@errorlines, $errorstring);
1654 $error_occurred = 1;
1655 $dir_error_occurred = 1;
1658 $installer::globals
::saved83dirmapping
{$1} = $4;
1663 push( @installer::globals
::globallogfileinfo
, "Read $n old directory 8.3 name mappings from $idtfile\n" );
1667 if ( $error_occurred )
1669 for ( my $i = 0; $i <= $#errorlines; $i++ )
1671 print "$errorlines[$i]";
1672 push( @installer::globals
::globallogfileinfo
, "$errorlines[$i]");
1674 installer
::exiter
::exit_program
("ERROR: Duplicate entries in saved mappings!", "read_saved_mappings");
1677 installer
::exiter
::exit_program
("ERROR: Windows patch shall be prepared, but environment variable PREVIOUS_IDT_DIR is not set!", "read_saved_mappings");
1680 installer
::logger
::include_timestamp_into_logfile
("Performance Info: Reading saved mappings end");
1685 # vim:set shiftwidth=4 softtabstop=4 expandtab: