← Index
NYTProf Performance Profile   « block view • line view • sub view »
For C:/lo/libo-master/solenv/bin/make_installer.pl
  Run on Mon Sep 24 00:52:54 2012
Reported on Mon Sep 24 07:34:55 2012

Filename/cygdrive/c/lo/libo-master/instsetoo_native/util/C:/lo/libo-master/solenv/bin/modules/installer/windows/msp.pm
StatementsExecuted 25 statements in 16.9ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1115.98ms6.56msinstaller::windows::msp::::BEGIN@39installer::windows::msp::BEGIN@39
1115.75ms6.24msinstaller::windows::msp::::BEGIN@41installer::windows::msp::BEGIN@41
111446µs543µsinstaller::windows::msp::::BEGIN@30installer::windows::msp::BEGIN@30
11121µs24µsinstaller::windows::msp::::BEGIN@40installer::windows::msp::BEGIN@40
11118µs20µsinstaller::windows::msp::::BEGIN@31installer::windows::msp::BEGIN@31
11117µs18µsinstaller::windows::msp::::BEGIN@38installer::windows::msp::BEGIN@38
11117µs19µsinstaller::windows::msp::::BEGIN@32installer::windows::msp::BEGIN@32
11117µs19µsinstaller::windows::msp::::BEGIN@34installer::windows::msp::BEGIN@34
11116µs18µsinstaller::windows::msp::::BEGIN@33installer::windows::msp::BEGIN@33
11116µs18µsinstaller::windows::msp::::BEGIN@37installer::windows::msp::BEGIN@37
11115µs42µsinstaller::windows::msp::::BEGIN@36installer::windows::msp::BEGIN@36
11115µs17µsinstaller::windows::msp::::BEGIN@35installer::windows::msp::BEGIN@35
0000s0sinstaller::windows::msp::::analyze_msimsp_logfileinstaller::windows::msp::analyze_msimsp_logfile
0000s0sinstaller::windows::msp::::change_imagefamilies_tableinstaller::windows::msp::change_imagefamilies_table
0000s0sinstaller::windows::msp::::change_patchmetadata_tableinstaller::windows::msp::change_patchmetadata_table
0000s0sinstaller::windows::msp::::change_patchsequence_tableinstaller::windows::msp::change_patchsequence_table
0000s0sinstaller::windows::msp::::change_properties_tableinstaller::windows::msp::change_properties_table
0000s0sinstaller::windows::msp::::change_targetimages_tableinstaller::windows::msp::change_targetimages_table
0000s0sinstaller::windows::msp::::change_upgradedimages_tableinstaller::windows::msp::change_upgradedimages_table
0000s0sinstaller::windows::msp::::check_and_save_tablesinstaller::windows::msp::check_and_save_tables
0000s0sinstaller::windows::msp::::collect_patch_file_destinationsinstaller::windows::msp::collect_patch_file_destinations
0000s0sinstaller::windows::msp::::convert_unicode_to_asciiinstaller::windows::msp::convert_unicode_to_ascii
0000s0sinstaller::windows::msp::::correct_langsinstaller::windows::msp::correct_langs
0000s0sinstaller::windows::msp::::correct_patchinstaller::windows::msp::correct_patch
0000s0sinstaller::windows::msp::::create_langstringinstaller::windows::msp::create_langstring
0000s0sinstaller::windows::msp::::create_msp_patchinstaller::windows::msp::create_msp_patch
0000s0sinstaller::windows::msp::::edit_tablesinstaller::windows::msp::edit_tables
0000s0sinstaller::windows::msp::::execute_msimspinstaller::windows::msp::execute_msimsp
0000s0sinstaller::windows::msp::::extract_all_tables_from_pcpfileinstaller::windows::msp::extract_all_tables_from_pcpfile
0000s0sinstaller::windows::msp::::get_filesequencestartinstaller::windows::msp::get_filesequencestart
0000s0sinstaller::windows::msp::::get_first_path_segmentinstaller::windows::msp::get_first_path_segment
0000s0sinstaller::windows::msp::::get_patchid_from_listinstaller::windows::msp::get_patchid_from_list
0000s0sinstaller::windows::msp::::get_patchsequenceinstaller::windows::msp::get_patchsequence
0000s0sinstaller::windows::msp::::get_patchtime_valueinstaller::windows::msp::get_patchtime_value
0000s0sinstaller::windows::msp::::get_requiredpatchfile_from_listinstaller::windows::msp::get_requiredpatchfile_from_list
0000s0sinstaller::windows::msp::::get_supersedeinstaller::windows::msp::get_supersede
0000s0sinstaller::windows::msp::::include_tables_into_pcpfileinstaller::windows::msp::include_tables_into_pcpfile
0000s0sinstaller::windows::msp::::install_installation_setsinstaller::windows::msp::install_installation_sets
0000s0sinstaller::windows::msp::::prepare_path_in_nopatchfilehashinstaller::windows::msp::prepare_path_in_nopatchfilehash
0000s0sinstaller::windows::msp::::set_mspfilenameinstaller::windows::msp::set_mspfilename
0000s0sinstaller::windows::msp::::synchronize_installation_setsinstaller::windows::msp::synchronize_installation_sets
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
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::msp;
29
30267µs2640µs
# spent 543µs (446+97) within installer::windows::msp::BEGIN@30 which was called: # once (446µs+97µs) by installer::BEGIN@76 at line 30
use File::Copy;
# spent 543µs making 1 call to installer::windows::msp::BEGIN@30 # spent 98µs making 1 call to Exporter::import
31256µs223µs
# spent 20µs (18+3) within installer::windows::msp::BEGIN@31 which was called: # once (18µs+3µs) by installer::BEGIN@76 at line 31
use installer::control;
# spent 20µs making 1 call to installer::windows::msp::BEGIN@31 # spent 3µs making 1 call to UNIVERSAL::import
32254µs221µs
# spent 19µs (17+2) within installer::windows::msp::BEGIN@32 which was called: # once (17µs+2µs) by installer::BEGIN@76 at line 32
use installer::converter;
# spent 19µs making 1 call to installer::windows::msp::BEGIN@32 # spent 2µs making 1 call to UNIVERSAL::import
33255µs220µs
# spent 18µs (16+2) within installer::windows::msp::BEGIN@33 which was called: # once (16µs+2µs) by installer::BEGIN@76 at line 33
use installer::exiter;
# spent 18µs making 1 call to installer::windows::msp::BEGIN@33 # spent 2µs making 1 call to UNIVERSAL::import
34254µs222µs
# spent 19µs (17+3) within installer::windows::msp::BEGIN@34 which was called: # once (17µs+3µs) by installer::BEGIN@76 at line 34
use installer::files;
# spent 19µs making 1 call to installer::windows::msp::BEGIN@34 # spent 3µs making 1 call to UNIVERSAL::import
35252µs219µs
# spent 17µs (15+2) within installer::windows::msp::BEGIN@35 which was called: # once (15µs+2µs) by installer::BEGIN@76 at line 35
use installer::globals;
# spent 17µs making 1 call to installer::windows::msp::BEGIN@35 # spent 2µs making 1 call to UNIVERSAL::import
36256µs269µs
# spent 42µs (15+27) within installer::windows::msp::BEGIN@36 which was called: # once (15µs+27µs) by installer::BEGIN@76 at line 36
use installer::logger;
# spent 42µs making 1 call to installer::windows::msp::BEGIN@36 # spent 27µs making 1 call to Exporter::import
37254µs220µs
# spent 18µs (16+2) within installer::windows::msp::BEGIN@37 which was called: # once (16µs+2µs) by installer::BEGIN@76 at line 37
use installer::pathanalyzer;
# spent 18µs making 1 call to installer::windows::msp::BEGIN@37 # spent 2µs making 1 call to UNIVERSAL::import
38252µs220µs
# spent 18µs (17+1) within installer::windows::msp::BEGIN@38 which was called: # once (17µs+1µs) by installer::BEGIN@76 at line 38
use installer::systemactions;
# spent 18µs making 1 call to installer::windows::msp::BEGIN@38 # spent 2µs making 1 call to UNIVERSAL::import
3921.21ms26.57ms
# spent 6.56ms (5.98+583µs) within installer::windows::msp::BEGIN@39 which was called: # once (5.98ms+583µs) by installer::BEGIN@76 at line 39
use installer::windows::admin;
# spent 6.56ms making 1 call to installer::windows::msp::BEGIN@39 # spent 10µs making 1 call to UNIVERSAL::import
40286µs227µs
# spent 24µs (21+3) within installer::windows::msp::BEGIN@40 which was called: # once (21µs+3µs) by installer::BEGIN@76 at line 40
use installer::windows::idtglobal;
# spent 24µs making 1 call to installer::windows::msp::BEGIN@40 # spent 3µs making 1 call to UNIVERSAL::import
41215.1ms26.24ms
# spent 6.24ms (5.75+487µs) within installer::windows::msp::BEGIN@41 which was called: # once (5.75ms+487µs) by installer::BEGIN@76 at line 41
use installer::windows::update;
# spent 6.24ms making 1 call to installer::windows::msp::BEGIN@41 # spent 7µs making 1 call to UNIVERSAL::import
42
43#################################################################################
44# Making all required administrative installations
45#################################################################################
46
47sub install_installation_sets
48{
49 my ($installationdir) = @_;
50
51 # Finding the msi database in the new installation set, that is located in $installationdir
52
53 my $msifiles = installer::systemactions::find_file_with_file_extension("msi", $installationdir);
54
55 if ( $#{$msifiles} < 0 ) { installer::exiter::exit_program("ERROR: Did not find msi database in directory $installationdir", "create_msp_patch"); }
56 if ( $#{$msifiles} > 0 ) { installer::exiter::exit_program("ERROR: Did find more than one msi database in directory $installationdir", "create_msp_patch"); }
57
58 my $newinstallsetdatabasepath = $installationdir . $installer::globals::separator . ${$msifiles}[0];
59 my $oldinstallsetdatabasepath = $installer::globals::updatedatabasepath;
60
61 # Creating temp directory again
62 installer::systemactions::create_directory_structure($installer::globals::temppath);
63
64 # Creating old installation directory
65 my $dirname = "admin";
66 my $installpath = $installer::globals::temppath . $installer::globals::separator . $dirname;
67 if ( ! -d $installpath) { installer::systemactions::create_directory($installpath); }
68
69 my $oldinstallpath = $installpath . $installer::globals::separator . "old";
70 my $newinstallpath = $installpath . $installer::globals::separator . "new";
71
72 if ( ! -d $oldinstallpath) { installer::systemactions::create_directory($oldinstallpath); }
73 if ( ! -d $newinstallpath) { installer::systemactions::create_directory($newinstallpath); }
74
75 my $olddatabase = installer::windows::admin::make_admin_install($oldinstallsetdatabasepath, $oldinstallpath);
76 my $newdatabase = installer::windows::admin::make_admin_install($newinstallsetdatabasepath, $newinstallpath);
77
78 if ( $^O =~ /cygwin/i ) {
79 $olddatabase = qx{cygpath -w "$olddatabase"};
80 $olddatabase =~ s/\s*$//g;
81 $newdatabase = qx{cygpath -w "$newdatabase"};
82 $newdatabase =~ s/\s*$//g;
83 }
84
85 return ($olddatabase, $newdatabase);
86}
87
88#################################################################################
89# Collecting the destinations of all files with flag PATCH in a hash.
90#################################################################################
91
92sub collect_patch_file_destinations
93{
94 my ( $filesarray ) = @_;
95
96 my %patchfiledestinations = ();
97 my %nopatchfiledestinations = ();
98 my $patchcounter = 0;
99 my $nopatchcounter = 0;
100
101 for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
102 {
103 my $onefile = ${$filesarray}[$i];
104 my $styles = "";
105
106 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'} };
107
108 if ( $styles =~ /\bPATCH\b/ )
109 {
110 $patchfiledestinations{$onefile->{'destination'}} = 1;
111 $patchcounter++;
112 }
113 else
114 {
115 $nopatchfiledestinations{$onefile->{'destination'}} = 1;
116 $nopatchcounter++;
117 }
118 }
119
120 return (\%patchfiledestinations, \%nopatchfiledestinations, $patchcounter, $nopatchcounter);
121}
122
123#################################################################################
124# Returning the first path segment of a path
125#################################################################################
126
127sub get_first_path_segment
128{
129 my ( $path ) = @_;
130
131 my $firstsegment = "";
132 my $remainder = $path;
133
134 if ( $path =~ /^\s*(.*?)[\/\\](.*)\s*$/ )
135 {
136 $firstsegment = $1;
137 $remainder = $2;
138 }
139
140 return ($firstsegment, $remainder);
141}
142
143#################################################################################
144# Finding the flexible path in the destinations, that are saved in
145# the hash $nopatchfiledestinations.
146#################################################################################
147
148sub prepare_path_in_nopatchfilehash
149{
150 my ($nopatchfiledestinations, $newpath) = @_;
151
152 my $infoline = "";
153 my $flexiblepath = "";
154 my $found = 0;
155 my %checked_destinations = ();
156
157 foreach my $onedestination ( keys %{$nopatchfiledestinations} )
158 {
159 $flexiblepath = "";
160 $found = 0;
161
162 my $found_first_segement = 1;
163 my $firstsegement = "";
164 my $fixedpath = $onedestination;
165 my $testfile = $newpath . $installer::globals::separator . $fixedpath;
166
167 while (( ! -f $testfile ) && ( $found_first_segement ))
168 {
169 $firstsegement = "";
170 ( $firstsegement, $fixedpath ) = get_first_path_segment($fixedpath);
171
172 if ( $firstsegement ne "" )
173 {
174 $found_first_segement = 1;
175 $flexiblepath = $flexiblepath . $firstsegement . $installer::globals::separator;
176 }
177 else
178 {
179 $found_first_segement = 0;
180 }
181
182 $testfile = $newpath . $installer::globals::separator . $fixedpath;
183 }
184
185 if ( -f $testfile ) { $found = 1; }
186
187 if ( $found ) { last; }
188 }
189
190 if ( ! $found ) { installer::exiter::exit_program("ERROR: Could not determine flexible destination path for msp patch creation!", "prepare_path_in_nopatchfilehash"); }
191
192 $infoline = "Setting flexible path for msp creation: $flexiblepath\n";
193 push( @installer::globals::logfileinfo, $infoline);
194
195 foreach my $onedestination ( keys %{$nopatchfiledestinations} )
196 {
197 $onedestination =~ s/^\s*\Q$flexiblepath\E//;
198 $checked_destinations{$onedestination} = 1;
199 }
200
201 return \%checked_destinations;
202}
203
204#################################################################################
205# Synchronizing the two installed products in that way, that only
206# files with flag PATCH are different.
207#################################################################################
208
209sub synchronize_installation_sets
210{
211 my ($olddatabase, $newdatabase, $filesarray) = @_;
212
213 my $infoline = "\nSynchronizing installed products because of PATCH flag\n";
214 push( @installer::globals::logfileinfo, $infoline);
215 $infoline = "Old product: $olddatabase\n";
216 push( @installer::globals::logfileinfo, $infoline);
217 $infoline = "New product: $newdatabase\n";
218 push( @installer::globals::logfileinfo, $infoline);
219
220 my ( $patchfiledestinations, $nopatchfiledestinations, $patchfilecounter, $nopatchfilecounter ) = collect_patch_file_destinations($filesarray);
221
222 $infoline = "Number of files with PATCH flag: $patchfilecounter\n";
223 push( @installer::globals::logfileinfo, $infoline);
224
225 $infoline = "Number of files without PATCH flag: $nopatchfilecounter\n";
226 push( @installer::globals::logfileinfo, $infoline);
227
228 foreach my $localfile ( sort keys %{$patchfiledestinations} )
229 {
230 $infoline = "\tPATCH file: $localfile\n";
231 push( @installer::globals::logfileinfo, $infoline);
232 }
233
234 my $oldpath = $olddatabase;
235 if ( $^O =~ /cygwin/i ) { $oldpath =~ s/\\/\//g; }
236 installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldpath);
237 $oldpath =~ s/\\\s*$//;
238 $oldpath =~ s/\/\s*$//;
239
240 my $newpath = $newdatabase;
241 if ( $^O =~ /cygwin/i ) { $newpath =~ s/\\/\//g; }
242 installer::pathanalyzer::get_path_from_fullqualifiedname(\$newpath);
243 $newpath =~ s/\\\s*$//;
244 $newpath =~ s/\/\s*$//;
245
246 # The destination path is not correct. destinations in the hash contain
247 # the flexible installation path, that is not part in the administrative installation
248 $nopatchfiledestinations = prepare_path_in_nopatchfilehash($nopatchfiledestinations, $newpath);
249
250 foreach my $onedestination ( keys %{$nopatchfiledestinations} )
251 {
252 my $source = $oldpath . $installer::globals::separator . $onedestination;
253 my $dest = $newpath . $installer::globals::separator . $onedestination;
254
255 if ( -f $source )
256 {
257 if ( -f $dest )
258 {
259 my $copyreturn = copy($source, $dest);
260 # installer::systemactions::copy_one_file($source, $dest);
261 # $infoline = "Synchronizing file: $source to $dest\n";
262 # push( @installer::globals::logfileinfo, $infoline);
263 }
264 else
265 {
266 $infoline = "Not synchronizing. Destination file \"$dest\" does not exist.\n";
267 push( @installer::globals::logfileinfo, $infoline);
268 }
269 }
270 else
271 {
272 $infoline = "Not synchronizing. Source file \"$source\" does not exist.\n";
273 push( @installer::globals::logfileinfo, $infoline);
274 }
275 }
276}
277
278#################################################################################
279# Extracting all tables from a pcp file
280#################################################################################
281
282sub extract_all_tables_from_pcpfile
283{
284 my ($fullpcpfilepath, $workdir) = @_;
285
286 my $msidb = "msidb.exe"; # Has to be in the path
287 my $infoline = "";
288 my $systemcall = "";
289 my $returnvalue = "";
290 my $extraslash = ""; # Has to be set for non-ActiveState perl
291
292 my $localfullpcpfile = $fullpcpfilepath;
293 my $localworkdir = $workdir;
294
295 if ( $^O =~ /cygwin/i ) {
296 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
297 $localfullpcpfile =~ s/\//\\\\/g;
298 $localworkdir =~ s/\//\\\\/g;
299 $extraslash = "\\";
300 }
301 if ( $^O =~ /linux/i ) {
302 $extraslash = "\\";
303 }
304
305 # Export of all tables by using "*"
306
307 $systemcall = $msidb . " -d " . $localfullpcpfile . " -f " . $localworkdir . " -e " . $extraslash . "*";
308 $returnvalue = system($systemcall);
309
310 $infoline = "Systemcall: $systemcall\n";
311 push( @installer::globals::logfileinfo, $infoline);
312
313 if ($returnvalue)
314 {
315 $infoline = "ERROR: Could not execute $systemcall !\n";
316 push( @installer::globals::logfileinfo, $infoline);
317 installer::exiter::exit_program("ERROR: Could not exclude tables from pcp file: $fullpcpfilepath !", "extract_all_tables_from_msidatabase");
318 }
319 else
320 {
321 $infoline = "Success: Executed $systemcall successfully!\n";
322 push( @installer::globals::logfileinfo, $infoline);
323 }
324}
325
326#################################################################################
327# Include tables into a pcp file
328#################################################################################
329
330sub include_tables_into_pcpfile
331{
332 my ($fullpcpfilepath, $workdir, $tables) = @_;
333
334 my $msidb = "msidb.exe"; # Has to be in the path
335 my $infoline = "";
336 my $systemcall = "";
337 my $returnvalue = "";
338
339 # Make all table 8+3 conform
340 my $alltables = installer::converter::convert_stringlist_into_array(\$tables, " ");
341
342 for ( my $i = 0; $i <= $#{$alltables}; $i++ )
343 {
344 my $tablename = ${$alltables}[$i];
345 $tablename =~ s/\s*$//;
346 my $namelength = length($tablename);
347 if ( $namelength > 8 )
348 {
349 my $newtablename = substr($tablename, 0, 8); # name, offset, length
350 my $oldfile = $workdir . $installer::globals::separator . $tablename . ".idt";
351 my $newfile = $workdir . $installer::globals::separator . $newtablename . ".idt";
352 if ( -f $newfile ) { unlink $newfile; }
353 installer::systemactions::copy_one_file($oldfile, $newfile);
354 }
355 }
356
357 # Import of tables
358
359 my $localworkdir = $workdir;
360 my $localfullpcpfilepath = $fullpcpfilepath;
361
362 if ( $^O =~ /cygwin/i ) {
363 # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
364 $localfullpcpfilepath =~ s/\//\\\\/g;
365 $localworkdir =~ s/\//\\\\/g;
366 }
367
368 $systemcall = $msidb . " -d " . $localfullpcpfilepath . " -f " . $localworkdir . " -i " . $tables;
369
370 $returnvalue = system($systemcall);
371
372 $infoline = "Systemcall: $systemcall\n";
373 push( @installer::globals::logfileinfo, $infoline);
374
375 if ($returnvalue)
376 {
377 $infoline = "ERROR: Could not execute $systemcall !\n";
378 push( @installer::globals::logfileinfo, $infoline);
379 installer::exiter::exit_program("ERROR: Could not include tables into pcp file: $fullpcpfilepath !", "include_tables_into_pcpfile");
380 }
381 else
382 {
383 $infoline = "Success: Executed $systemcall successfully!\n";
384 push( @installer::globals::logfileinfo, $infoline);
385 }
386}
387
388#################################################################################
389# Calling msimsp.exe
390#################################################################################
391
392sub execute_msimsp
393{
394 my ($fullpcpfilename, $mspfilename, $localmspdir) = @_;
395
396 my $msimsp = "msimsp.exe"; # Has to be in the path
397 my $infoline = "";
398 my $systemcall = "";
399 my $returnvalue = "";
400 my $logfilename = $localmspdir . $installer::globals::separator . "msimsp.log";
401
402 # Using a specific temp for each msimsp.exe process
403 # Creating temp directory again (should already have happened)
404 installer::systemactions::create_directory_structure($installer::globals::temppath);
405
406 # Creating old installation directory
407 my $dirname = "msimsptemp";
408 my $msimsptemppath = $installer::globals::temppath . $installer::globals::separator . $dirname;
409 if ( ! -d $msimsptemppath) { installer::systemactions::create_directory($msimsptemppath); }
410
411 # r:\msvc9p\PlatformSDK\v6.1\bin\msimsp.exe -s c:\patch\hotfix_qfe1.pcp -p c:\patch\patch_ooo3_m2_m3.msp -l c:\patch\patch_ooo3_m2_m3.log
412
413 if ( -f $logfilename ) { unlink $logfilename; }
414
415 my $localfullpcpfilename = $fullpcpfilename;
416 my $localmspfilename = $mspfilename;
417 my $locallogfilename = $logfilename;
418 my $localmsimsptemppath = $msimsptemppath;
419
420 if ( $^O =~ /cygwin/i ) {
421 # msimsp.exe really wants backslashes. (And double escaping because system() expands the string.)
422 $localfullpcpfilename =~ s/\//\\\\/g;
423 $locallogfilename =~ s/\//\\\\/g;
424
425 $localmspfilename =~ s/\\/\\\\/g; # path already contains backslash
426
427 $localmsimsptemppath = qx{cygpath -w "$localmsimsptemppath"};
428 $localmsimsptemppath =~ s/\\/\\\\/g;
429 $localmsimsptemppath =~ s/\s*$//g;
430 }
431
432 $systemcall = $msimsp . " -s " . $localfullpcpfilename . " -p " . $localmspfilename . " -l " . $locallogfilename . " -f " . $localmsimsptemppath;
433 installer::logger::print_message( "... $systemcall ...\n" );
434
435 $returnvalue = system($systemcall);
436
437 $infoline = "Systemcall: $systemcall\n";
438 push( @installer::globals::logfileinfo, $infoline);
439
440 if ($returnvalue)
441 {
442 $infoline = "ERROR: Could not execute $systemcall !\n";
443 push( @installer::globals::logfileinfo, $infoline);
444 installer::exiter::exit_program("ERROR: Could not execute $systemcall !", "execute_msimsp");
445 }
446 else
447 {
448 $infoline = "Success: Executed $systemcall successfully!\n";
449 push( @installer::globals::logfileinfo, $infoline);
450 }
451
452 return $logfilename;
453}
454
455####################################################################
456# Checking existence and saving all tables, that need to be edited
457####################################################################
458
459sub check_and_save_tables
460{
461 my ($tablelist, $workdir) = @_;
462
463 my $tables = installer::converter::convert_stringlist_into_array(\$tablelist, " ");
464
465 for ( my $i = 0; $i <= $#{$tables}; $i++ )
466 {
467 my $filename = ${$tables}[$i];
468 $filename =~ s/\s*$//;
469 my $fullfilename = $workdir . $installer::globals::separator . $filename . ".idt";
470
471 if ( ! -f $fullfilename ) { installer::exiter::exit_program("ERROR: Required idt file could not be found: \"$fullfilename\"!", "check_and_save_tables"); }
472
473 my $savfilename = $fullfilename . ".sav";
474 installer::systemactions::copy_one_file($fullfilename, $savfilename);
475 }
476}
477
478####################################################################
479# Setting the languages for the service packs
480####################################################################
481
482sub create_langstring
483{
484 my ( $languagesarrayref ) = @_;
485
486 my $langstring = "";
487 for ( my $i = 0; $i <= $#{$languagesarrayref}; $i++ ) { $langstring = $langstring . "_" . ${$languagesarrayref}[$i]; }
488
489 return $langstring;
490}
491
492####################################################################
493# Setting the name of the msp database
494####################################################################
495
496sub set_mspfilename
497{
498 my ($allvariables, $mspdir, $languagesarrayref) = @_;
499
500 my $databasename = $allvariables->{'PRODUCTNAME'};
501 $databasename = lc($databasename);
502 $databasename =~ s/\.//g;
503 $databasename =~ s/\-//g;
504 $databasename =~ s/\s//g;
505
506 if ( $allvariables->{'MSPPRODUCTVERSION'} ) { $databasename = $databasename . $allvariables->{'MSPPRODUCTVERSION'}; }
507
508 # possibility to overwrite the name with variable DATABASENAME
509 # if ( $allvariables->{'DATABASENAME'} ) { $databasename = $allvariables->{'DATABASENAME'}; }
510
511 # Adding patch info to database name
512 # if ( $installer::globals::buildid ) { $databasename = $databasename . "_" . $installer::globals::buildid; }
513
514 # if ( $allvariables->{'VENDORPATCHVERSION'} ) { $databasename = $databasename . "_" . $allvariables->{'VENDORPATCHVERSION'}; }
515
516
517 if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 ))
518 {
519 my $windowspatchlevel = 0;
520 if ( $allvariables->{'MSPPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'MSPPATCHLEVEL'}; }
521 $databasename = $databasename . "_servicepack_" . $windowspatchlevel;
522 my $languagestring = create_langstring($languagesarrayref);
523 $databasename = $databasename . $languagestring;
524 }
525 else
526 {
527 my $hotfixaddon = "hotfix_";
528 $hotfixaddon = $hotfixaddon . $installer::globals::buildid;
529 my $cwsname = "";
530 if ( $allvariables->{'OVERWRITE_CWSNAME'} ) { $hotfixaddon = $allvariables->{'OVERWRITE_CWSNAME'}; }
531 $databasename = $databasename . "_" . $hotfixaddon;
532 }
533
534 $databasename = $databasename . ".msp";
535
536 my $fullmspname = $mspdir . $installer::globals::separator . $databasename;
537
538 if ( $^O =~ /cygwin/i ) { $fullmspname =~ s/\//\\/g; }
539
540 return $fullmspname;
541}
542
543####################################################################
544# Editing table Properties
545####################################################################
546
547sub change_properties_table
548{
549 my ($localmspdir, $mspfilename) = @_;
550
551 my $infoline = "Changing content of table \"Properties\"\n";
552 push( @installer::globals::logfileinfo, $infoline);
553
554 my $filename = $localmspdir . $installer::globals::separator . "Properties.idt";
555 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_properties_table"); }
556
557 my $filecontent = installer::files::read_file($filename);
558
559
560 my $guidref = installer::windows::msiglobal::get_guid_list(1, 1);
561 ${$guidref}[0] =~ s/\s*$//; # removing ending spaces
562 my $patchcode = "\{" . ${$guidref}[0] . "\}";
563
564 # Setting "PatchOutputPath"
565 my $found_patchoutputpath = 0;
566 my $found_patchguid = 0;
567
568 for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
569 {
570 if ( ${$filecontent}[$i] =~ /^\s*PatchOutputPath\t(.*?)\s*$/ )
571 {
572 my $oldvalue = $1;
573 ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$mspfilename/;
574 $found_patchoutputpath = 1;
575 }
576
577 if ( ${$filecontent}[$i] =~ /^\s*PatchGUID\t(.*?)\s*$/ )
578 {
579 my $oldvalue = $1;
580 ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$patchcode/;
581 $found_patchguid = 1;
582 }
583 }
584
585 if ( ! $found_patchoutputpath )
586 {
587 my $newline = "PatchOutputPath\t$mspfilename\n";
588 push(@{$filecontent}, $newline);
589 }
590
591 if ( ! $found_patchguid )
592 {
593 my $newline = "PatchGUID\t$patchcode\n";
594 push(@{$filecontent}, $newline);
595 }
596
597 # saving file
598 installer::files::save_file($filename, $filecontent);
599}
600
601####################################################################
602# Editing table TargetImages
603####################################################################
604
605sub change_targetimages_table
606{
607 my ($localmspdir, $olddatabase) = @_;
608
609 my $infoline = "Changing content of table \"TargetImages\"\n";
610 push( @installer::globals::logfileinfo, $infoline);
611
612 my $filename = $localmspdir . $installer::globals::separator . "TargetImages.idt";
613 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_targetimages_table"); }
614
615 my $filecontent = installer::files::read_file($filename);
616 my @newcontent = ();
617
618 # Copying the header
619 for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
620
621 #Adding all targets
622 my $newline = "T1\t$olddatabase\t\tU1\t1\t0x00000922\t1\n";
623 push(@newcontent, $newline);
624
625 # saving file
626 installer::files::save_file($filename, \@newcontent);
627}
628
629####################################################################
630# Editing table UpgradedImages
631####################################################################
632
633sub change_upgradedimages_table
634{
635 my ($localmspdir, $newdatabase) = @_;
636
637 my $infoline = "Changing content of table \"UpgradedImages\"\n";
638 push( @installer::globals::logfileinfo, $infoline);
639
640 my $filename = $localmspdir . $installer::globals::separator . "UpgradedImages.idt";
641 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_upgradedimages_table"); }
642
643 my $filecontent = installer::files::read_file($filename);
644 my @newcontent = ();
645
646 # Copying the header
647 for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
648
649 # Syntax: Upgraded MsiPath PatchMsiPath SymbolPaths Family
650
651 # default values
652 my $upgraded = "U1";
653 my $msipath = $newdatabase;
654 my $patchmsipath = "";
655 my $symbolpaths = "";
656 my $family = "22334455";
657
658 if ( $#{$filecontent} >= 3 )
659 {
660 my $line = ${$filecontent}[3];
661 if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
662 {
663 $upgraded = $1;
664 $patchmsipath = $3;
665 $symbolpaths = $4;
666 $family = $5;
667 }
668 }
669
670 #Adding sequence line, saving PatchFamily
671 my $newline = "$upgraded\t$msipath\t$patchmsipath\t$symbolpaths\t$family\n";
672 push(@newcontent, $newline);
673
674 # saving file
675 installer::files::save_file($filename, \@newcontent);
676}
677
678####################################################################
679# Editing table ImageFamilies
680####################################################################
681
682sub change_imagefamilies_table
683{
684 my ($localmspdir) = @_;
685
686 my $infoline = "Changing content of table \"ImageFamilies\"\n";
687 push( @installer::globals::logfileinfo, $infoline);
688
689 my $filename = $localmspdir . $installer::globals::separator . "ImageFamilies.idt";
690 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_imagefamilies_table"); }
691
692 my $filecontent = installer::files::read_file($filename);
693 my @newcontent = ();
694
695 # Copying the header
696 for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
697
698 # Syntax: Family MediaSrcPropName MediaDiskId FileSequenceStart DiskPrompt VolumeLabel
699 # "FileSequenceStart has to be set
700
701 # Default values:
702
703 my $family = "22334455";
704 my $mediasrcpropname = "MediaSrcPropName";
705 my $mediadiskid = "2";
706 my $filesequencestart = get_filesequencestart();
707 my $diskprompt = "";
708 my $volumelabel = "";
709
710 if ( $#{$filecontent} >= 3 )
711 {
712 my $line = ${$filecontent}[3];
713 if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
714 {
715 $family = $1;
716 $mediasrcpropname = $2;
717 $mediadiskid = $3;
718 $diskprompt = $5;
719 $volumelabel = $6;
720 }
721 }
722
723 #Adding sequence line
724 my $newline = "$family\t$mediasrcpropname\t$mediadiskid\t$filesequencestart\t$diskprompt\t$volumelabel\n";
725 push(@newcontent, $newline);
726
727 # saving file
728 installer::files::save_file($filename, \@newcontent);
729}
730
731####################################################################
732# Setting start sequence for patch
733####################################################################
734
735sub get_filesequencestart
736{
737 my $sequence = 1000; # default
738
739 if ( $installer::globals::updatelastsequence ) { $sequence = $installer::globals::updatelastsequence + 500; }
740
741 return $sequence;
742}
743
744####################################################################
745# Setting time value into pcp file
746# Format mm/dd/yyyy hh:mm
747####################################################################
748
749sub get_patchtime_value
750{
751 # Syntax: 8/8/2008 11:55
752 my $minute = (localtime())[1];
753 my $hour = (localtime())[2];
754 my $day = (localtime())[3];
755 my $month = (localtime())[4];
756 my $year = 1900 + (localtime())[5];
757
758 $month++; # zero based month
759 if ( $minute < 10 ) { $minute = "0" . $minute; }
760 if ( $hour < 10 ) { $hour = "0" . $hour; }
761
762 my $timestring = $month . "/" . $day . "/" . $year . " " . $hour . ":" . $minute;
763
764 return $timestring;
765}
766
767#################################################################################
768# Checking, if this is the correct database.
769#################################################################################
770
771sub correct_langs
772{
773 my ($langs, $languagestringref) = @_;
774
775 my $correct_langs = 0;
776
777 # Comparing $langs with $languagestringref
778
779 my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ",");
780 my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_");
781
782 my $not_included = 0;
783 foreach my $onelang ( keys %{$langlisthash} )
784 {
785 if ( ! exists($langstringhash->{$onelang}) )
786 {
787 $not_included = 1;
788 last;
789 }
790 }
791
792 if ( ! $not_included )
793 {
794 foreach my $onelanguage ( keys %{$langstringhash} )
795 {
796 if ( ! exists($langlisthash->{$onelanguage}) )
797 {
798 $not_included = 1;
799 last;
800 }
801 }
802
803 if ( ! $not_included ) { $correct_langs = 1; }
804 }
805
806 return $correct_langs;
807}
808
809#################################################################################
810# Searching for the path to the reference database for this special product.
811#################################################################################
812
813sub get_patchid_from_list
814{
815 my ($filecontent, $languagestringref, $filename) = @_;
816
817 my $patchid = "";
818
819 for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
820 {
821 my $line = ${$filecontent}[$i];
822 if ( $line =~ /^\s*$/ ) { next; } # empty line
823 if ( $line =~ /^\s*\#/ ) { next; } # comment line
824
825 if ( $line =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/ )
826 {
827 my $langs = $1;
828 my $localpatchid = $2;
829
830 if ( correct_langs($langs, $languagestringref) )
831 {
832 $patchid = $localpatchid;
833 last;
834 }
835 }
836 else
837 {
838 installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_patchid_from_list");
839 }
840 }
841
842 return $patchid;
843}
844
845####################################################################
846# Editing table PatchMetadata
847####################################################################
848
849sub change_patchmetadata_table
850{
851 my ($localmspdir, $allvariables, $languagestringref) = @_;
852
853 my $infoline = "Changing content of table \"PatchMetadata\"\n";
854 push( @installer::globals::logfileinfo, $infoline);
855
856 my $filename = $localmspdir . $installer::globals::separator . "PatchMetadata.idt";
857 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchmetadata_table"); }
858
859 my $filecontent = installer::files::read_file($filename);
860 my @newcontent = ();
861
862 # Syntax: Company Property Value
863 # Interesting properties: "Classification" and "CreationTimeUTC"
864
865 my $classification_set = 0;
866 my $creationtime_set = 0;
867 my $targetproductname_set = 0;
868 my $manufacturer_set = 0;
869 my $displayname_set = 0;
870 my $description_set = 0;
871 my $allowremoval_set = 0;
872
873 my $defaultcompany = "";
874
875 my $classificationstring = "Classification";
876 my $classificationvalue = "Hotfix";
877 if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $classificationvalue = "ServicePack"; }
878
879 my $allowremovalstring = "AllowRemoval";
880 my $allowremovalvalue = "1";
881 if (( exists($allvariables->{'MSPALLOWREMOVAL'}) ) && ( $allvariables->{'MSPALLOWREMOVAL'} == 0 )) { $allowremovalvalue = 0; }
882
883 my $timestring = "CreationTimeUTC";
884 # Syntax: 8/8/2008 11:55
885 my $timevalue = get_patchtime_value();
886
887 my $targetproductnamestring = "TargetProductName";
888 my $targetproductnamevalue = $allvariables->{'PRODUCTNAME'};
889 if ( $allvariables->{'PROPERTYTABLEPRODUCTNAME'} ) { $targetproductnamevalue = $allvariables->{'PROPERTYTABLEPRODUCTNAME'}; }
890
891 my $manufacturerstring = "ManufacturerName";
892 my $manufacturervalue = $ENV{'OOO_VENDOR'};
893 if ( $installer::globals::longmanufacturer ) { $manufacturervalue = $installer::globals::longmanufacturer; }
894
895 my $displaynamestring = "DisplayName";
896 my $descriptionstring = "Description";
897 my $displaynamevalue = "";
898 my $descriptionvalue = "";
899
900 my $base = $allvariables->{'PRODUCTNAME'} . " " . $allvariables->{'PRODUCTVERSION'};
901 if ( $installer::globals::languagepack || $installer::globals::helppack ) { $base = $targetproductnamevalue; }
902
903 my $windowspatchlevel = 0;
904 if ( $allvariables->{'WINDOWSPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'WINDOWSPATCHLEVEL'}; }
905
906 my $displayaddon = "";
907 if ( $allvariables->{'PATCHDISPLAYADDON'} ) { $displayaddon = $allvariables->{'PATCHDISPLAYADDON'}; }
908
909 my $patchsequence = get_patchsequence($allvariables);
910
911 if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 ))
912 {
913 $displaynamevalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid;
914 $descriptionvalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid;
915 }
916 else
917 {
918 $displaynamevalue = $base . " Hotfix " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid;
919 $descriptionvalue = $base . " Hotfix " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid;
920 $displaynamevalue =~ s/ / /g;
921 $descriptionvalue =~ s/ / /g;
922 $displaynamevalue =~ s/ / /g;
923 $descriptionvalue =~ s/ / /g;
924 $displaynamevalue =~ s/ / /g;
925 $descriptionvalue =~ s/ / /g;
926 }
927
928 if ( $allvariables->{'MSPPATCHNAMELIST'} )
929 {
930 my $patchnamelistfile = $allvariables->{'MSPPATCHNAMELIST'};
931 $patchnamelistfile = $installer::globals::idttemplatepath . $installer::globals::separator . $patchnamelistfile;
932 if ( ! -f $patchnamelistfile ) { installer::exiter::exit_program("ERROR: Could not find file \"$patchnamelistfile\".", "change_patchmetadata_table"); }
933 my $filecontent = installer::files::read_file($patchnamelistfile);
934
935 # Get name and path of reference database
936 my $patchid = get_patchid_from_list($filecontent, $languagestringref, $patchnamelistfile);
937
938 if ( $patchid eq "" ) { installer::exiter::exit_program("ERROR: Could not find file patchid in file \"$patchnamelistfile\" for language(s) \"$$languagestringref\".", "change_patchmetadata_table"); }
939
940 # Setting language specific patch id
941 }
942
943 for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
944 {
945 if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\s*$/ )
946 {
947 my $company = $1;
948 my $property = $2;
949 my $value = $3;
950
951 if ( $property eq $classificationstring )
952 {
953 ${$filecontent}[$i] = "$company\t$property\t$classificationvalue\n";
954 $classification_set = 1;
955 }
956
957 if ( $property eq $allowremovalstring )
958 {
959 ${$filecontent}[$i] = "$company\t$property\t$allowremovalvalue\n";
960 $allowremoval_set = 1;
961 }
962
963 if ( $property eq $timestring )
964 {
965 ${$filecontent}[$i] = "$company\t$property\t$timevalue\n";
966 $creationtime_set = 1;
967 }
968
969 if ( $property eq $targetproductnamestring )
970 {
971 ${$filecontent}[$i] = "$company\t$property\t$targetproductnamevalue\n";
972 $targetproductname_set = 1;
973 }
974
975 if ( $property eq $manufacturerstring )
976 {
977 ${$filecontent}[$i] = "$company\t$property\t$manufacturervalue\n";
978 $manufacturer_set = 1;
979 }
980
981 if ( $property eq $displaynamestring )
982 {
983 ${$filecontent}[$i] = "$company\t$property\t$displaynamevalue\n";
984 $displayname_set = 1;
985 }
986
987 if ( $property eq $descriptionstring )
988 {
989 ${$filecontent}[$i] = "$company\t$property\t$descriptionvalue\n";
990 $description_set = 1;
991 }
992 }
993
994 push(@newcontent, ${$filecontent}[$i]);
995 }
996
997 if ( ! $classification_set )
998 {
999 my $line = "$defaultcompany\t$classificationstring\t$classificationvalue\n";
1000 push(@newcontent, $line);
1001 }
1002
1003 if ( ! $allowremoval_set )
1004 {
1005 my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n";
1006 push(@newcontent, $line);
1007 }
1008
1009 if ( ! $allowremoval_set )
1010 {
1011 my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n";
1012 push(@newcontent, $line);
1013 }
1014
1015 if ( ! $creationtime_set )
1016 {
1017 my $line = "$defaultcompany\t$timestring\t$timevalue\n";
1018 push(@newcontent, $line);
1019 }
1020
1021 if ( ! $targetproductname_set )
1022 {
1023 my $line = "$defaultcompany\t$targetproductnamestring\t$targetproductnamevalue\n";
1024 push(@newcontent, $line);
1025 }
1026
1027 if ( ! $manufacturer_set )
1028 {
1029 my $line = "$defaultcompany\t$manufacturerstring\t$manufacturervalue\n";
1030 push(@newcontent, $line);
1031 }
1032
1033 if ( ! $displayname_set )
1034 {
1035 my $line = "$defaultcompany\t$displaynamestring\t$displaynamevalue\n";
1036 push(@newcontent, $line);
1037 }
1038
1039 if ( ! $description_set )
1040 {
1041 my $line = "$defaultcompany\t$descriptionstring\t$descriptionvalue\n";
1042 push(@newcontent, $line);
1043 }
1044
1045 # saving file
1046 installer::files::save_file($filename, \@newcontent);
1047}
1048
1049####################################################################
1050# Editing table PatchSequence
1051####################################################################
1052
1053sub change_patchsequence_table
1054{
1055 my ($localmspdir, $allvariables) = @_;
1056
1057 my $infoline = "Changing content of table \"PatchSequence\"\n";
1058 push( @installer::globals::logfileinfo, $infoline);
1059
1060 my $filename = $localmspdir . $installer::globals::separator . "PatchSequence.idt";
1061 if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchsequence_table"); }
1062
1063 my $filecontent = installer::files::read_file($filename);
1064 my @newcontent = ();
1065
1066 # Copying the header
1067 for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
1068
1069 # Syntax: PatchFamily Target Sequence Supersede
1070
1071 my $patchfamily = "SO";
1072 my $target = "";
1073 my $patchsequence = get_patchsequence($allvariables);
1074 my $supersede = get_supersede($allvariables);
1075
1076 if ( $#{$filecontent} >= 3 )
1077 {
1078 my $line = ${$filecontent}[3];
1079 if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\s$/ )
1080 {
1081 $patchfamily = $1;
1082 $target = $2;
1083 }
1084 }
1085
1086 #Adding sequence line, saving PatchFamily
1087 my $newline = "$patchfamily\t$target\t$patchsequence\t$supersede\n";
1088 push(@newcontent, $newline);
1089
1090 # saving file
1091 installer::files::save_file($filename, \@newcontent);
1092}
1093
1094####################################################################
1095# Setting supersede, "0" for Hotfixes, "1" for ServicePack
1096####################################################################
1097
1098sub get_supersede
1099{
1100 my ( $allvariables ) = @_;
1101
1102 my $supersede = 0; # if not defined, this is a Hotfix
1103
1104 if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $supersede = 1; }
1105
1106 return $supersede;
1107}
1108
1109####################################################################
1110# Setting the sequence of the patch
1111####################################################################
1112
1113sub get_patchsequence
1114{
1115 my ( $allvariables ) = @_;
1116
1117 my $patchsequence = "1.0";
1118
1119 if ( ! $allvariables->{'PACKAGEVERSION'} ) { installer::exiter::exit_program("ERROR: PACKAGEVERSION must be set for msp patch creation!", "get_patchsequence"); }
1120
1121 my $packageversion = $allvariables->{'PACKAGEVERSION'};
1122
1123 if ( $packageversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ )
1124 {
1125 my $major = $1;
1126 my $minor = $2;
1127 my $micro = $3;
1128 my $concat = 100 * $minor + $micro;
1129 $packageversion = $major . "\." . $concat;
1130 }
1131 my $vendornumber = 0;
1132 if ( $allvariables->{'VENDORPATCHVERSION'} ) { $vendornumber = $allvariables->{'VENDORPATCHVERSION'}; }
1133 $patchsequence = $packageversion . "\." . $installer::globals::buildid . "\." . $vendornumber;
1134
1135 if ( $allvariables->{'PATCHSEQUENCE'} ) { $patchsequence = $allvariables->{'PATCHSEQUENCE'}; }
1136
1137 return $patchsequence;
1138}
1139
1140####################################################################
1141# Editing all tables from pcp file, that need to be edited
1142####################################################################
1143
1144sub edit_tables
1145{
1146 my ($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref) = @_;
1147
1148 # table list contains: my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence";
1149
1150 change_properties_table($localmspdir, $mspfilename);
1151 change_targetimages_table($localmspdir, $olddatabase);
1152 change_upgradedimages_table($localmspdir, $newdatabase);
1153 change_imagefamilies_table($localmspdir);
1154 change_patchmetadata_table($localmspdir, $allvariables, $languagestringref);
1155 change_patchsequence_table($localmspdir, $allvariables);
1156}
1157
1158#################################################################################
1159# Checking, if this is the correct database.
1160#################################################################################
1161
1162sub correct_patch
1163{
1164 my ($product, $pro, $langs, $languagestringref) = @_;
1165
1166 my $correct_patch = 0;
1167
1168 # Comparing $product with $installer::globals::product and
1169 # $pro with $installer::globals::pro and
1170 # $langs with $languagestringref
1171
1172 my $product_is_good = 0;
1173
1174 my $localproduct = $installer::globals::product;
1175 if ( $installer::globals::languagepack ) { $localproduct = $localproduct . "LanguagePack"; }
1176 elsif ( $installer::globals::helppack ) { $localproduct = $localproduct . "HelpPack"; }
1177
1178 if ( $product eq $localproduct ) { $product_is_good = 1; }
1179
1180 if ( $product_is_good )
1181 {
1182 my $pro_is_good = 0;
1183
1184 if ((( $pro eq "pro" ) && ( $installer::globals::pro )) || (( $pro eq "nonpro" ) && ( ! $installer::globals::pro ))) { $pro_is_good = 1; }
1185
1186 if ( $pro_is_good )
1187 {
1188 my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ",");
1189 my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_");
1190
1191 my $not_included = 0;
1192 foreach my $onelang ( keys %{$langlisthash} )
1193 {
1194 if ( ! exists($langstringhash->{$onelang}) )
1195 {
1196 $not_included = 1;
1197 last;
1198 }
1199 }
1200
1201 if ( ! $not_included )
1202 {
1203 foreach my $onelanguage ( keys %{$langstringhash} )
1204 {
1205 if ( ! exists($langlisthash->{$onelanguage}) )
1206 {
1207 $not_included = 1;
1208 last;
1209 }
1210 }
1211
1212 if ( ! $not_included ) { $correct_patch = 1; }
1213 }
1214 }
1215 }
1216
1217 return $correct_patch;
1218}
1219
1220#################################################################################
1221# Searching for the path to the required patch for this special product.
1222#################################################################################
1223
1224sub get_requiredpatchfile_from_list
1225{
1226 my ($filecontent, $languagestringref, $filename) = @_;
1227
1228 my $patchpath = "";
1229
1230 for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
1231 {
1232 my $line = ${$filecontent}[$i];
1233 if ( $line =~ /^\s*$/ ) { next; } # empty line
1234 if ( $line =~ /^\s*\#/ ) { next; } # comment line
1235
1236 if ( $line =~ /^\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*$/ )
1237 {
1238 my $product = $1;
1239 my $pro = $2;
1240 my $langs = $3;
1241 my $path = $4;
1242
1243 if (( $pro ne "pro" ) && ( $pro ne "nonpro" )) { installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename. Only \"pro\" or \"nonpro\" allowed in column 1! Line: \"$line\"", "get_databasename_from_list"); }
1244
1245 if ( correct_patch($product, $pro, $langs, $languagestringref) )
1246 {
1247 $patchpath = $path;
1248 last;
1249 }
1250 }
1251 else
1252 {
1253 installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_requiredpatchfile_from_list");
1254 }
1255 }
1256
1257 return $patchpath;
1258}
1259
1260##################################################################
1261# Converting unicode file to ascii
1262# to be more precise: uft-16 little endian to ascii
1263##################################################################
1264
1265sub convert_unicode_to_ascii
1266{
1267 my ( $filename ) = @_;
1268
1269 my @localfile = ();
1270
1271 my $savfilename = $filename . "_before.unicode";
1272 installer::systemactions::copy_one_file($filename, $savfilename);
1273
1274 open( IN, "<:encoding(UTF16-LE)", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii");
1275 while ( $line = <IN> ) {
1276 push @localfile, $line;
1277 }
1278 close( IN );
1279
1280 if ( open( OUT, ">", $filename ) )
1281 {
1282 print OUT @localfile;
1283 close(OUT);
1284 }
1285}
1286
1287####################################################################
1288# Analyzing the log file created by msimsp.exe to find all
1289# files included into the patch.
1290####################################################################
1291
1292sub analyze_msimsp_logfile
1293{
1294 my ($logfile, $filesarray) = @_;
1295
1296 # Reading log file after converting from utf-16 (LE) to ascii
1297 convert_unicode_to_ascii($logfile);
1298 my $logfilecontent = installer::files::read_file($logfile);
1299
1300 # Creating hash from $filesarray: unique file name -> destination of file
1301 my %filehash = ();
1302 my %destinationcollector = ();
1303
1304 for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
1305 {
1306 my $onefile = ${$filesarray}[$i];
1307
1308 # Only collecting files with "uniquename" and "destination"
1309 if (( exists($onefile->{'uniquename'}) ) && ( exists($onefile->{'uniquename'}) ))
1310 {
1311 my $uniquefilename = $onefile->{'uniquename'};
1312 my $destpath = $onefile->{'destination'};
1313 $filehash{$uniquefilename} = $destpath;
1314 }
1315 }
1316
1317 # Analyzing log file of msimsp.exe, finding all changed files
1318 # and searching all destinations of unique file names.
1319 # Content in log file: "INFO File Key: <file key> is modified"
1320 # Collecting content in @installer::globals::patchfilecollector
1321
1322 for ( my $i = 0; $i <= $#{$logfilecontent}; $i++ )
1323 {
1324 if ( ${$logfilecontent}[$i] =~ /Key\:\s*(.*?) is modified\s*$/ )
1325 {
1326 my $filekey = $1;
1327 if ( exists($filehash{$filekey}) ) { $destinationcollector{$filehash{$filekey}} = 1; }
1328 else { installer::exiter::exit_program("ERROR: Could not find file key \"$filekey\" in file collector.", "analyze_msimsp_logfile"); }
1329 }
1330 }
1331
1332 foreach my $onedest ( sort keys %destinationcollector ) { push(@installer::globals::patchfilecollector, "$onedest\n"); }
1333
1334}
1335
1336####################################################################
1337# Creating msp patch files for Windows
1338####################################################################
1339
1340sub create_msp_patch
1341{
1342 my ($installationdir, $includepatharrayref, $allvariables, $languagestringref, $languagesarrayref, $filesarray) = @_;
1343
1344 my $force = 1; # print this message even in 'quiet' mode
1345 installer::logger::print_message( "\n******************************************\n" );
1346 installer::logger::print_message( "... creating msp installation set ...\n", $force );
1347 installer::logger::print_message( "******************************************\n" );
1348
1349 $installer::globals::creating_windows_installer_patch = 1;
1350
1351 my @needed_files = ("msimsp.exe"); # only required for patch creation process
1352 installer::control::check_needed_files_in_path(\@needed_files);
1353
1354 installer::logger::include_header_into_logfile("Creating msp installation sets:");
1355
1356 my $firstdir = $installationdir;
1357 installer::pathanalyzer::get_path_from_fullqualifiedname(\$firstdir);
1358
1359 my $lastdir = $installationdir;
1360 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$lastdir);
1361
1362 if ( $lastdir =~ /\./ ) { $lastdir =~ s/\./_msp_inprogress\./ }
1363 else { $lastdir = $lastdir . "_msp_inprogress"; }
1364
1365 # Removing existing directory "_native_packed_inprogress" and "_native_packed_witherror" and "_native_packed"
1366
1367 my $mspdir = $firstdir . $lastdir;
1368 if ( -d $mspdir ) { installer::systemactions::remove_complete_directory($mspdir); }
1369
1370 my $olddir = $mspdir;
1371 $olddir =~ s/_inprogress/_witherror/;
1372 if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
1373
1374 $olddir = $mspdir;
1375 $olddir =~ s/_inprogress//;
1376 if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
1377
1378 # Creating the new directory for new installation set
1379 installer::systemactions::create_directory($mspdir);
1380
1381 $installer::globals::saveinstalldir = $mspdir;
1382
1383 installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting product installation");
1384
1385 # Installing both installation sets
1386 installer::logger::print_message( "... installing products ...\n" );
1387 my ($olddatabase, $newdatabase) = install_installation_sets($installationdir);
1388
1389 installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting synchronization of installation sets");
1390
1391 # Synchronizing installed products, allowing only different files with PATCH flag
1392 installer::logger::print_message( "... synchronizing installation sets ...\n" );
1393 synchronize_installation_sets($olddatabase, $newdatabase, $filesarray);
1394
1395 installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting pcp file creation");
1396
1397 # Create pcp file
1398 installer::logger::print_message( "... creating pcp file ...\n" );
1399
1400 my $localmspdir = installer::systemactions::create_directories("msp", $languagestringref);
1401
1402 if ( ! $allvariables->{'PCPFILENAME'} ) { installer::exiter::exit_program("ERROR: Property \"PCPFILENAME\" has to be defined.", "create_msp_patch"); }
1403 my $pcpfilename = $allvariables->{'PCPFILENAME'};
1404
1405 if ( $installer::globals::languagepack ) { $pcpfilename =~ s/.pcp\s*$/languagepack.pcp/; }
1406 elsif ( $installer::globals::helppack ) { $pcpfilename =~ s/.pcp\s*$/helppack.pcp/; }
1407
1408 # Searching the pcp file in the include paths
1409 my $fullpcpfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$pcpfilename, $includepatharrayref, 1);
1410 if ( $$fullpcpfilenameref eq "" ) { installer::exiter::exit_program("ERROR: pcp file not found: $pcpfilename !", "create_msp_patch"); }
1411 my $fullpcpfilenamesource = $$fullpcpfilenameref;
1412
1413 # Copying pcp file
1414 my $fullpcpfilename = $localmspdir . $installer::globals::separator . $pcpfilename;
1415 installer::systemactions::copy_one_file($fullpcpfilenamesource, $fullpcpfilename);
1416
1417 # a. Extracting tables from msi database: msidb.exe -d <msifile> -f <directory> -e File Media, ...
1418 # b. Changing content of msi database in tables: File, Media, Directory, FeatureComponent
1419 # c. Including tables into msi database: msidb.exe -d <msifile> -f <directory> -i File Media, ...
1420
1421 # Unpacking tables from pcp file
1422 extract_all_tables_from_pcpfile($fullpcpfilename, $localmspdir);
1423
1424 # Tables, that need to be edited
1425 my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence"; # required tables
1426
1427 # Saving all tables
1428 check_and_save_tables($tablelist, $localmspdir);
1429
1430 # Setting the name of the new msp file
1431 my $mspfilename = set_mspfilename($allvariables, $mspdir, $languagesarrayref);
1432
1433 # Editing tables
1434 edit_tables($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref);
1435
1436 # Adding edited tables into pcp file
1437 include_tables_into_pcpfile($fullpcpfilename, $localmspdir, $tablelist);
1438
1439 # Start msimsp.exe
1440 installer::logger::include_timestamp_into_logfile("\nPerformance Info: Starting msimsp.exe");
1441 my $msimsplogfile = execute_msimsp($fullpcpfilename, $mspfilename, $localmspdir);
1442
1443 # Copy final installation set next to msp file
1444 installer::logger::include_timestamp_into_logfile("\nPerformance Info: Copying installation set");
1445 installer::logger::print_message( "... copying installation set ...\n" );
1446
1447 my $oldinstallationsetpath = $installer::globals::updatedatabasepath;
1448
1449 if ( $^O =~ /cygwin/i ) { $oldinstallationsetpath =~ s/\\/\//g; }
1450
1451 installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldinstallationsetpath);
1452 installer::systemactions::copy_complete_directory($oldinstallationsetpath, $mspdir);
1453
1454 # Copying additional patches into the installation set, if required
1455 if (( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ) && ( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ne "" ) && ( ! $installer::globals::languagepack ) && ( ! $installer::globals::helppack ))
1456 {
1457 my $filename = $allvariables->{'ADDITIONALREQUIREDPATCHES'};
1458
1459 my $fullfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1);
1460 if ( $$fullfilenameref eq "" ) { installer::exiter::exit_program("ERROR: Could not find file with required patches, although it is defined: $filename !", "create_msp_patch"); }
1461 my $fullfilename = $$fullfilenameref;
1462
1463 # Reading list file
1464 my $listfile = installer::files::read_file($fullfilename);
1465
1466 # Get name and path of reference database
1467 my $requiredpatchfile = get_requiredpatchfile_from_list($listfile, $languagestringref, $fullfilename);
1468 if ( $requiredpatchfile eq "" ) { installer::exiter::exit_program("ERROR: Could not find path to required patch in file $fullfilename for language(s) $$languagestringref!", "create_msp_patch"); }
1469
1470 # Copying patch file
1471 installer::systemactions::copy_one_file($requiredpatchfile, $mspdir);
1472 # my $infoline = "Copy $requiredpatchfile to $mspdir\n";
1473 # push( @installer::globals::logfileinfo, $infoline);
1474 }
1475
1476 # Find all files included into the patch
1477 # Analyzing the msimsp log file $msimsplogfile
1478 analyze_msimsp_logfile($msimsplogfile, $filesarray);
1479
1480 # Done
1481 installer::logger::include_timestamp_into_logfile("\nPerformance Info: msp creation done");
1482
1483 return $mspdir;
1484}
1485
1486111µs1;