summaryrefslogtreecommitdiff
path: root/solenv/bin/modules
diff options
context:
space:
mode:
Diffstat (limited to 'solenv/bin/modules')
-rw-r--r--solenv/bin/modules/installer/control.pm4
-rw-r--r--solenv/bin/modules/installer/epmfile.pm2
-rw-r--r--solenv/bin/modules/installer/globals.pm22
-rw-r--r--solenv/bin/modules/installer/languages.pm47
-rw-r--r--solenv/bin/modules/installer/parameter.pm3
-rw-r--r--solenv/bin/modules/installer/patch/FileOperations.pm333
-rw-r--r--solenv/bin/modules/installer/patch/FileSequenceList.pm159
-rw-r--r--solenv/bin/modules/installer/patch/InstallationSet.pm467
-rw-r--r--solenv/bin/modules/installer/patch/Msi.pm342
-rw-r--r--solenv/bin/modules/installer/patch/MsiRow.pm160
-rw-r--r--solenv/bin/modules/installer/patch/MsiTable.pm274
-rw-r--r--solenv/bin/modules/installer/patch/ReleasesList.pm210
-rw-r--r--solenv/bin/modules/installer/patch/Tools.pm47
-rw-r--r--solenv/bin/modules/installer/patch/Version.pm74
-rw-r--r--solenv/bin/modules/installer/scriptitems.pm20
-rw-r--r--solenv/bin/modules/installer/windows/component.pm5
-rw-r--r--solenv/bin/modules/installer/windows/directory.pm15
-rw-r--r--solenv/bin/modules/installer/windows/file.pm193
-rw-r--r--solenv/bin/modules/installer/windows/media.pm143
-rw-r--r--solenv/bin/modules/installer/windows/mergemodule.pm1668
-rw-r--r--solenv/bin/modules/installer/windows/msiglobal.pm279
-rw-r--r--solenv/bin/modules/installer/windows/msp.pm1493
-rw-r--r--solenv/bin/modules/installer/windows/property.pm12
-rw-r--r--solenv/bin/modules/installer/windows/registry.pm11
-rw-r--r--solenv/bin/modules/installer/windows/update.pm595
-rw-r--r--solenv/bin/modules/installer/ziplist.pm134
-rw-r--r--solenv/bin/modules/par2script/globals.pm3
-rw-r--r--solenv/bin/modules/pre2par/globals.pm3
28 files changed, 2249 insertions, 4469 deletions
diff --git a/solenv/bin/modules/installer/control.pm b/solenv/bin/modules/installer/control.pm
index 2974b949e5f1..51edf8d3b8e8 100644
--- a/solenv/bin/modules/installer/control.pm
+++ b/solenv/bin/modules/installer/control.pm
@@ -321,7 +321,7 @@ sub filter_log_error ($$$$)
# Remove all filenames that contain the word "Error".
my $work_string = $message;
- $work_string =~ s/Error\.(idt|mlf|ulf|html|hpp|ipp)//g;
+ $work_string =~ s/Error\.(idt|mlf|ulf|idl|html|hpp|ipp)//g;
if ($work_string =~ /\bError\b/i)
{
@@ -497,7 +497,7 @@ sub check_updatepack
# try to write into $shipdrive
- my $directory = $installer::globals::product . "_" . $installer::globals::compiler . "_" . $installer::globals::buildid . "_" . $installer::globals::languageproducts[0] . "_test_$$";
+ my $directory = $installer::globals::product . "_" . $installer::globals::compiler . "_" . $installer::globals::buildid . "_" . $installer::globals::languageproduct . "_test_$$";
$directory =~ s/\,/\_/g; # for the list of languages
$directory =~ s/\-/\_/g; # for en-US, pt-BR, ...
$directory = $shipdrive . $installer::globals::separator . $directory;
diff --git a/solenv/bin/modules/installer/epmfile.pm b/solenv/bin/modules/installer/epmfile.pm
index e877595b35ac..38cff5d3569c 100644
--- a/solenv/bin/modules/installer/epmfile.pm
+++ b/solenv/bin/modules/installer/epmfile.pm
@@ -2312,7 +2312,7 @@ sub log_rpm_info
$infoline = "$rpmout\n";
$infoline =~ s/error/e_r_r_o_r/gi; # avoiding log problems
- $installer::logger::Lang->printf($infoline);
+ $installer::logger::Lang->print($infoline);
}
}
else
diff --git a/solenv/bin/modules/installer/globals.pm b/solenv/bin/modules/installer/globals.pm
index f4dcd0ff382f..04d14ea6d735 100644
--- a/solenv/bin/modules/installer/globals.pm
+++ b/solenv/bin/modules/installer/globals.pm
@@ -113,7 +113,7 @@ BEGIN
$required_dotnet_version = "2.0.0.0";
$productextension = "";
- @languageproducts = ();
+ $languageproduct = undef;
$build = "";
$minor = "";
$lastminor = "";
@@ -226,24 +226,14 @@ BEGIN
@linkrpms = ();
$archiveformat = "";
$minorupgradekey = "";
- $updatelastsequence = 0;
- $updatesequencecounter = 0;
- $updatedatabase = 0;
- $updatedatabasepath = "";
$pfffileexists = 0;
$pffcabfilename = "ooobasis3.0_pff.cab";
- $mergemodulenumber = 0;
- %allmergemodulefilesequences = ();
- %newupdatefiles = ();
- %allusedupdatesequences = ();
- %mergemodulefiles = ();
$mergefiles_added_into_collector = 0;
$creating_windows_installer_patch = 0;
$strip = 1;
$globallogging = 0;
- $globalloggingform21 = 1;
$logfilename = "logfile.log"; # the default logfile name for global errors
# @logfileinfo = ();
# @errorlogfileinfo = ();
@@ -273,7 +263,6 @@ BEGIN
$isopensourceproduct = 1;
$manufacturer = "";
$longmanufacturer = "";
- $sundirname = "Oracle";
$codefilename = "codes.txt";
$componentfilename = "components.txt";
$productcode = "";
@@ -292,7 +281,6 @@ BEGIN
$pwfile = "";
$pfxfile = "";
- %mergemodules = ();
%merge_media_line = ();
%merge_allfeature_hash = ();
%merge_alldirectory_hash = ();
@@ -375,7 +363,6 @@ BEGIN
@pcfdiffcomment = ();
@epmdifflist = ();
$desktoplinkexists = 0;
- $sundirexists = 0;
$analyze_spellcheckerlanguage = 0;
%spellcheckerlanguagehash = ();
%spellcheckerfilehash = ();
@@ -403,11 +390,8 @@ BEGIN
$officedirhostname = "";
$basisdirhostname = "";
$uredirhostname = "";
- $sundirhostname = "";
$officedirgid = "";
$basisdirgid = "";
- $uredirgid = "";
- $sundirgid = "";
%sign_extensions = ("dll" => "1", "exe" => "1", "cab" => "1");
%treestyles = ();
@@ -418,13 +402,10 @@ BEGIN
%usedtreeconditions = ();
%moduledestination = ();
- $one_cab_file = 0;
$fix_number_of_cab_files = 1;
- $cab_file_per_component = 0;
$cabfilecompressionlevel = 2;
$number_of_cabfiles = 1; # only for $fix_number_of_cab_files = 1
$include_cab_in_msi = 0;
- $use_packages_for_cabs = 0;
$msidatabasename = "";
$prepare_winpatch = 0;
$previous_idt_dir = "";
@@ -451,7 +432,6 @@ BEGIN
$postprocess_specialepm = 0;
$postprocess_standardepm = 0;
- $mergemodules_analyzed = 0;
$starttime = "";
diff --git a/solenv/bin/modules/installer/languages.pm b/solenv/bin/modules/installer/languages.pm
index d184ff7f66ee..030956d0c529 100644
--- a/solenv/bin/modules/installer/languages.pm
+++ b/solenv/bin/modules/installer/languages.pm
@@ -30,31 +30,46 @@ use installer::globals;
use installer::remover;
use installer::ziplist;
-#############################################################################
-# Analyzing the laguage list parameter and language list from zip list file
-#############################################################################
+=head2 analyze_languagelist()
-sub analyze_languagelist
-{
- my $first = $installer::globals::languagelist;
+ Convert $installer::globals::languagelist into $installer::globals::languageproduct.
+
+ That is now just a replacement of '_' with ','.
+
+ $installer::globals::languageproduct (specified by the -l option
+ on the command line) can contain multiple languages separated by
+ '_' to specify multilingual builds.
- $first =~ s/\_/\,/g; # substituting "_" by ",", in case of dmake definition 01_49
+ Separation by '#' to build multiple languages (single or
+ multilingual) in one make_installer.pl run is not supported
+ anymore. Call make_installer.pl with all languages separately instead:
+ make_installer.pl -l L1#L2
+ ->
+ make_installer.pl -l L1
+ make_installer.pl -l L2
- # Products are separated by a "#", if defined in zip-list by a "|". But "get_info_about_languages"
- # substitutes already "|" to "#". This procedure only knows "#" as product separator.
- # Different languages for one product are separated by ",". But on the command line the "_" is used.
- # Therefore "_" is replaced by "," at the beginning of this procedure.
+=cut
+sub analyze_languagelist()
+{
+ my $languageproduct = $installer::globals::languagelist;
+
+ $languageproduct =~ s/\_/\,/g; # substituting "_" by ",", in case of dmake definition 01_49
- while ($first =~ /^(\S+)\#(\S+?)$/) # Minimal matching, to keep the order of languages
+ if ($languageproduct =~ /\#/)
{
- $first = $1;
- my $last = $2;
- unshift(@installer::globals::languageproducts, $last);
+ installer::exiter::exit_program(
+ "building more than one language (or language set) is not supported anymore\n"
+ ."please replace one call of 'make_installer.pl -l language1#language2'\n"
+ ."with two calls 'make_installer.pl -l language1' and 'make_installer.pl -l language2'",
+ "installer::language::analyze_languagelist");
}
- unshift(@installer::globals::languageproducts, $first);
+ $installer::globals::languageproduct = $languageproduct;
}
+
+
+
####################################################
# Reading languages from zip list file
####################################################
diff --git a/solenv/bin/modules/installer/parameter.pm b/solenv/bin/modules/installer/parameter.pm
index faa3cc1fde2a..eb4209b82c7d 100644
--- a/solenv/bin/modules/installer/parameter.pm
+++ b/solenv/bin/modules/installer/parameter.pm
@@ -618,8 +618,7 @@ sub outputparameter ()
else { push(@output, "Not unzipping ARCHIVE files\n"); }
if (!($installer::globals::languages_defined_in_productlist))
{
- push(@output, "Languages:\n");
- foreach my $element (@installer::globals::languageproducts) { push(@output, "\t$element\n"); }
+ push(@output, sprintf("Languages: %s\n", $installer::globals::languageproduct));
}
else
{
diff --git a/solenv/bin/modules/installer/patch/FileOperations.pm b/solenv/bin/modules/installer/patch/FileOperations.pm
new file mode 100644
index 000000000000..931db2eca654
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/FileOperations.pm
@@ -0,0 +1,333 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::FileOperations;
+
+use File::Basename;
+use File::Copy;
+use IO::Compress::Bzip2;
+use IO::Uncompress::Bunzip2;
+
+my $CompressionMethod = "bzip2";
+
+
+=head1 NAME
+
+ package installer::patch::FileOperations - Class for collecting, checking and executing file operations.
+
+=cut
+
+
+sub new ($)
+{
+ my ($class) = (@_);
+
+ my $self = {
+ 'operations' => []
+ };
+ bless($self, $class);
+
+ return $self;
+}
+
+
+
+
+sub AddCopyOperation ($$$)
+{
+ my ($self, $source_name, $target_name) = @_;
+
+ push
+ @{$self->{'operations'}},
+ [
+ 'copy',
+ $source_name,
+ $target_name
+ ];
+}
+
+
+
+
+sub AddMakeDirectoryOperation ($$)
+{
+ my ($self, $path) = @_;
+
+ push
+ @{$self->{'operations'}},
+ [
+ 'mkdir',
+ $path
+ ];
+}
+
+
+
+
+sub AddCompressOperation ($$)
+{
+ my ($self, $filename) = @_;
+
+ push
+ @{$self->{'operations'}},
+ [
+ 'compress',
+ $filename
+ ];
+}
+
+
+
+
+sub AddUncompressOperation ($$$)
+{
+ my ($self, $source_name, $target_name) = @_;
+
+ push
+ @{$self->{'operations'}},
+ [
+ 'uncompress',
+ $source_name,
+ $target_name
+ ];
+}
+
+
+
+
+sub Check ($)
+{
+ my ($self) = @_;
+
+ # Keep track of which directories or files would be created to check if
+ # operations that depend on these files will succeed.
+ my %files = ();
+ my %directories = ();
+
+ my @error_messages = ();
+ foreach my $operation (@{$self->{'operations'}})
+ {
+ my $command = $operation->[0];
+
+ if ($command eq "copy")
+ {
+ my ($source_name, $destination_name) = ($operation->[1], $operation->[2]);
+ if ( ! -f $source_name)
+ {
+ push @error_messages, sprintf("%s is not a regular file and can not be copied", $source_name);
+ }
+ my $destination_path = dirname($destination_name);
+ if ( ! -d $destination_path && ! defined $directories{$destination_path})
+ {
+ push @error_messages, sprintf("destination path %s does not exist", $destination_path);
+ }
+ if ( -f $destination_name)
+ {
+ # The destination file already exists. We have to overwrite it.
+ if ( ! -w $destination_name)
+ {
+ push @error_messges, sprintf("destination file %s exists but can not be overwritten", $destination_name);
+ }
+ }
+ $files{$destination_name} = 1;
+ }
+ elsif ($command eq "mkdir")
+ {
+ my $path = $operation->[1];
+ if ( -d $path)
+ {
+ # Directory already exists. That is OK, the mkdir command will be silently ignored.
+ }
+ else
+ {
+ $directories{$path} = 1;
+ }
+ }
+ elsif ($command eq "compress")
+ {
+ my $filename = $operation->[1];
+ if ( ! -f $filename && ! defined $files{$filename})
+ {
+ # File does not exist and will not be created by an earlier operation.
+ push @error_messages, sprintf("file %s does not exist and can not be compressed", $filename);
+ }
+ }
+ elsif ($command eq "uncompress")
+ {
+ my ($source_filename, $destination_filename) = ($operation->[1], $operation->[2]);
+ if ($CompressionMethod eq "bzip2")
+ {
+ $source_filename .= ".bz2";
+ }
+ if ( ! -f $source_filename && ! defined $files{$source_filename})
+ {
+ # File does not exist and will not be created by an earlier operation.
+ push @error_messages, sprintf("file %s does not exist and can not be decompressed", $source_filename);
+ }
+ if ( -f $destination_filename && ! -w $destination_filename)
+ {
+ # Destination file aleady exists but can not be replaced.
+ push @error_messages, sprintf("compress destination file %s exists but can not be replaced", $destination_filename);
+ }
+ }
+ else
+ {
+ push @error_messages, sprintf("unknown operation %s", $command);
+ }
+ }
+
+ return @error_messages;
+}
+
+
+
+
+sub CheckAndExecute ($)
+{
+ my ($self) = @_;
+
+ my @error_messages = $self->Check();
+ if (scalar @error_messages > 0)
+ {
+ $installer::logger::Lang->printf("can not execute all operations:\n");
+ for my $message (@error_messages)
+ {
+ $installer::logger::Lang->printf("ERROR: %s\n", $message);
+ }
+ return 0;
+ }
+ else
+ {
+ return $self->Execute();
+ }
+}
+
+
+
+
+sub Execute ($)
+{
+ my ($self) = @_;
+
+ foreach my $operation (@{$self->{'operations'}})
+ {
+ my $command = $operation->[0];
+
+ if ($command eq "copy")
+ {
+ my ($source_name, $destination_name) = ($operation->[1], $operation->[2]);
+ $installer::logger::Lang->printf("copy from %s\n to %s\n", $source_name, $destination_name);
+ if ( ! $DryRun)
+ {
+ my $result = copy($source_name, $destination_name);
+ if ( ! $result)
+ {
+ $installer::logger::Lang->printf("ERROR: copying from %s to %s failed",
+ $source_name, $destination_name);
+ }
+ }
+ }
+ elsif ($command eq "mkdir")
+ {
+ my $path = $operation->[1];
+ if ( -d $path)
+ {
+ # Path exists already. Do nothing.
+ }
+ else
+ {
+ $installer::logger::Lang->printf("creating directory %s\n", $path);
+ if ( ! $DryRun)
+ {
+ if (File::Path::make_path($path, {'mode' => 0775}) == 0)
+ {
+ $installer::logger::Lang->printf("could not create directory %s\n", $path);
+ }
+ }
+ }
+ }
+ elsif ($command eq "compress")
+ {
+ my $filename = $operation->[1];
+ $installer::logger::Lang->printf("compressing %s\n", $filename);
+ if ( ! $DryRun)
+ {
+ my $result = 0;
+ if ($CompressionMethod eq "bzip2")
+ {
+ $result = IO::Compress::Bzip2::bzip2($filename => $filename.".bz2");
+ }
+ if ($result == 0)
+ {
+ $installer::logger::Lang->printf("ERROR: could not compress %s\n", $filename);
+ }
+ else
+ {
+ unlink($filename);
+ }
+ }
+ }
+ elsif ($command eq "uncompress")
+ {
+ my ($source_name, $destination_name) = ($operation->[1], $operation->[2]);
+ if ($CompressionMethod eq "bzip2")
+ {
+ $source_name .= ".bz2";
+ }
+ $installer::logger::Lang->printf("uncompressing %s to %s\n", $source_name, $destination_name);
+
+ my $destination_base_name = basename($destination_name);
+
+ if ( ! $DryRun)
+ {
+ my $result = 0;
+ if ($CompressionMethod eq "bzip2")
+ {
+ $result = IO::Uncompress::Bunzip2::bunzip2($source_name => $destination_name);
+ }
+ if ($result == 0)
+ {
+ $installer::logger::Lang->printf("ERROR: failed to extract content of '%s' from '%s'\n",
+ $destination_name, $source_name);
+ return 0;
+ }
+ }
+ }
+
+ else
+ {
+ die "unknown operation $command\n";
+ }
+ }
+
+ return 1;
+}
+
+
+
+sub GetOperationCount ($)
+{
+ my ($self) = @_;
+ return scalar @{$self->{'operations'}};
+}
+
+
+1;
diff --git a/solenv/bin/modules/installer/patch/FileSequenceList.pm b/solenv/bin/modules/installer/patch/FileSequenceList.pm
new file mode 100644
index 000000000000..6c607d8314e8
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/FileSequenceList.pm
@@ -0,0 +1,159 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::FileSequenceList;
+
+use XML::LibXML;
+use strict;
+
+=head1 NAME
+
+ FileSequenceList.pm - Class for retrieving and processing the 'Sequence' values of the MSI 'File' table.
+
+=cut
+
+=head2 new($class)
+
+ Create a new FileSequenceList object.
+
+=cut
+sub new ($)
+{
+ my ($class) = @_;
+
+ my $self = {
+ 'data' => undef
+ };
+ bless($self, $class);
+
+ return $self;
+}
+
+
+
+
+sub SetFromFileList ($$)
+{
+ my ($self, $files) = @_;
+
+ my %data = map {$_->{'uniquename'} => $_->{'sequencenumber'}} @$files;
+ $self->{'data'} = \%data;
+}
+
+
+
+
+sub SetFromMap ($$)
+{
+ my ($self, $map) = @_;
+
+ $self->{'data'} = $map;
+}
+
+
+
+
+sub GetFileCount ($)
+{
+ my ($self) = @_;
+
+ return scalar keys %{$self->{'data'}};
+}
+
+
+
+
+=head2 GetSequenceNumbers ($files)
+
+ $files is a hash that maps unique file names (File->File) to sequence
+ numbers (File->Sequence). The later is (expected to be) initially unset and
+ is set in this method.
+
+ For new files -- entries in the given $files that do not exist in the 'data'
+ member -- no sequence numbers are defined.
+
+ When there are removed files -- entries in the 'data' member that do not
+ exist in the given $files -- then a list of these files is returned. In
+ that case the given $files remain unmodified.
+
+ The returned list is empty when everyting is OK.
+
+=cut
+sub GetSequenceNumbers ($$)
+{
+ my ($self, $files) = @_;
+
+ # Check if files have been removed.
+ my @missing = ();
+ foreach my $name (keys %{$self->{'data'}})
+ {
+ if ( ! defined $files->{$name})
+ {
+ push @missing, $name;
+ }
+ }
+ if (scalar @missing > 0)
+ {
+ # Yes. Return the names of the removed files.
+ return @missing;
+ }
+
+ # No files where removed. Set the sequence numbers.
+ foreach my $name (keys %$files)
+ {
+ $files->{$name} = $self->{'data'}->{$name};
+ }
+ return ();
+}
+
+
+
+
+sub GetDifference ($$)
+{
+ my ($self, $other) = @_;
+
+ # Create maps for easy reference.
+ my (@files_in_both, @files_in_self, @files_in_other);
+ foreach my $name (keys %{$self->{'data'}})
+ {
+ if (defined $other->{'data'}->{$name})
+ {
+ push @files_in_both, $name;
+ }
+ else
+ {
+ push @files_in_self, $name;
+ }
+ }
+ foreach my $name (keys %{$self->{'data'}})
+ {
+ if ( ! defined $self->{'data'}->{$name})
+ {
+ push @files_in_other, $name;
+ }
+ }
+
+ return (\@files_in_both, \@files_in_self, \@files_in_other);
+}
+
+
+1;
diff --git a/solenv/bin/modules/installer/patch/InstallationSet.pm b/solenv/bin/modules/installer/patch/InstallationSet.pm
new file mode 100644
index 000000000000..67ff1fe4e0b7
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/InstallationSet.pm
@@ -0,0 +1,467 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::InstallationSet;
+
+use installer::patch::Tools;
+use installer::patch::Version;
+use installer::logger;
+
+
+my $Unpacker = "/c/Program\\ Files/7-Zip/7z.exe";
+
+=head1 NAME
+
+ package installer::patch::InstallationSet - Functions for handling installation sets
+
+=head1 DESCRIPTION
+
+ This package contains functions for unpacking the .exe files that
+ are created by the NSIS installer creator and the .cab files in
+ the installation sets.
+
+=cut
+
+sub UnpackExe ($$)
+{
+ my ($filename, $destination_path) = @_;
+
+ $installer::logger::Info->printf("unpacking installation set to '%s'\n", $destination_path);
+
+ # Unpack to a temporary path and change its name to the destination path
+ # only when the unpacking has completed successfully.
+ my $temporary_destination_path = $destination_path . ".tmp";
+ File::Path::make_path($temporary_destination_path);
+
+ my $windows_filename = installer::patch::Tools::CygpathToWindows($filename);
+ my $windows_destination_path = installer::patch::Tools::CygpathToWindows($temporary_destination_path);
+ my $command = join(" ",
+ $Unpacker,
+ "x", "-o".$windows_destination_path,
+ $windows_filename);
+ my $result = qx($command);
+
+ # Check the existence of the .cab files.
+ my $cab_filename = File::Spec->catfile($temporary_destination_path, "openoffice1.cab");
+ if ( ! -f $cab_filename)
+ {
+ installer::logger::PrintError("cab file '%s' was not extracted from installation set\n", $cab_filename);
+ return 0;
+ }
+ if (rename($temporary_destination_path, $destination_path) == 0)
+ {
+ installer::logger::PrintError("can not rename temporary extraction directory\n");
+ return 0;
+ }
+ return 1;
+}
+
+
+
+
+=head2 UnpackCab($cab_filename, $destination_path)
+
+ Unpacking the cabinet file inside an .exe installation set is a
+ three step process because there is no directory information stored
+ inside the cab file. This has to be taken from the 'File' and
+ 'Directory' tables in the .msi file.
+
+ 1. Setup the directory structure of all files in the cab from the 'File' and 'Directory' tables in the msi.
+
+ 2. Unpack the cab file.
+
+ 3. Move the files to their destination directories.
+
+=cut
+sub UnpackCab ($$$)
+{
+ my ($cab_filename, $msi, $destination_path) = @_;
+
+ # Step 1
+ # Extract the directory structure from the 'File' and 'Directory' tables in the given msi.
+ $installer::logger::Info->printf("setting up directory tree\n");
+ my $file_table = $msi->GetTable("File");
+ my $file_to_directory_map = $msi->GetFileToDirectoryMap();
+
+ # Step 2
+ # Unpack the .cab file to a temporary path.
+ my $temporary_destination_path = $destination_path . ".tmp";
+ if ( -d $temporary_destination_path)
+ {
+ # Temporary directory already exists => cab file has already been unpacked (flat), nothing to do.
+ $installer::logger::Info->printf("cab file has already been unpacked to flat structure\n");
+ }
+ else
+ {
+ UnpackCabFlat($cab_filename, $temporary_destination_path, $file_table);
+ }
+
+ # Step 3
+ # Move the files to their destinations.
+ File::Path::make_path($destination_path);
+ $installer::logger::Info->printf("moving files to their directories\n");
+ my $count = 0;
+ foreach my $file_row (@{$file_table->GetAllRows()})
+ {
+ my $unique_name = $file_row->GetValue('File');
+ my $directory_full_names = $file_to_directory_map->{$unique_name};
+ my ($source_full_name, $target_full_name) = @$directory_full_names;
+
+ my $flat_filename = File::Spec->catfile($temporary_destination_path, $unique_name);
+ my $dir_path = File::Spec->catfile($destination_path, $source_full_name);
+ my $dir_filename = File::Spec->catfile($dir_path, $unique_name);
+
+ printf("%d: making path %s and copying %s to %s\n",
+ $count,
+ $dir_path,
+ $unique_name,
+ $dir_filename);
+ File::Path::make_path($dir_path);
+ File::Copy::move($flat_filename, $dir_filename);
+
+ ++$count;
+ }
+
+ # Cleanup. Remove the temporary directory. It should be empty by now.
+ rmdir($temporary_destination_path);
+}
+
+
+
+
+=head2 UnpackCabFlat ($cab_filename, $destination_path, $file_table)
+
+ Unpack the flat file structure of the $cab_filename to $destination_path.
+
+ In order to detect and handle an incomplete (arborted) previous
+ extraction, the cab file is unpacked to a temprorary directory
+ that after successful extraction is renamed to $destination_path.
+
+=cut
+sub UnpackCabFlat ($$$)
+{
+ my ($cab_filename, $destination_path, $file_table) = @_;
+
+ # Unpack the .cab file to a temporary path (note that
+ # $destination_path may alreay bee a temporary path). Using a
+ # second one prevents the lengthy flat unpacking to be repeated
+ # when another step fails.
+
+ $installer::logger::Info->printf("unpacking cab file\n");
+ my $temporary_destination_path = $destination_path . ".tmp";
+ File::Path::make_path($temporary_destination_path);
+ my $windows_cab_filename = installer::patch::Tools::CygpathToWindows($cab_filename);
+ my $windows_destination_path = installer::patch::Tools::CygpathToWindows($temporary_destination_path);
+ my $command = join(" ",
+ $Unpacker,
+ "x", "-o".$windows_destination_path,
+ $windows_cab_filename,
+ "-y");
+ printf("running command '%s'\n", $command);
+ open my $cmd, $command."|";
+ my $extraction_count = 0;
+ my $file_count = $file_table->GetRowCount();
+ while (<$cmd>)
+ {
+ my $message = $_;
+ chomp($message);
+ ++$extraction_count;
+ printf("%4d/%4d %3.2f%% \r",
+ $extraction_count,
+ $file_count,
+ $extraction_count*100/$file_count);
+ }
+ close $cmd;
+ printf("extraction done \n");
+
+ rename($temporary_destination_path, $destination_path)
+ || installer::logger::PrintError(
+ "can not rename the temporary directory '%s' to '%s'\n",
+ $temporary_destination_path,
+ $destination_path);
+}
+
+
+
+
+=head GetUnpackedMsiPath ($version, $language, $package_format, $product)
+
+ Convenience function that returns where a downloadable installation set is extracted to.
+
+=cut
+sub GetUnpackedMsiPath ($$$$)
+{
+ my ($version, $language, $package_format, $product) = @_;
+
+ return File::Spec->catfile(
+ GetUnpackedPath($version, $language, $package_format, $product),
+ "unpacked_msi");
+}
+
+
+
+
+=head GetUnpackedCabPath ($version, $language, $package_format, $product)
+
+ Convenience function that returns where a cab file is extracted
+ (with injected directory structure from the msi file) to.
+
+=cut
+sub GetUnpackedCabPath ($$$$)
+{
+ my ($version, $language, $package_format, $product) = @_;
+
+ return File::Spec->catfile(
+ GetUnpackedPath($version, $language, $package_format, $product),
+ "unpacked_cab");
+}
+
+
+
+
+=head2 GetUnpackedPath($version, $language, $package_format, $product)
+
+ Internal function for creating paths to where archives are unpacked.
+
+=cut
+sub GetUnpackedPath ($$$$)
+{
+ my ($version, $language, $package_format, $product) = @_;
+
+ return File::Spec->catfile(
+ $ENV{'SRC_ROOT'},
+ "instsetoo_native",
+ $ENV{'INPATH'},
+ $product,
+ $package_format,
+ installer::patch::Version::ArrayToDirectoryName(installer::patch::Version::StringToNumberArray($version)),
+ $language);
+}
+
+
+
+
+=head2 Download($language, $release_data, $filename)
+
+ Download an installation set to $filename. The URL for the
+ download is taken from $release_data, a snippet from the
+ instsetoo_native/data/releases.xml file.
+
+=cut
+sub Download ($$$)
+{
+ my ($language, $release_data, $filename) = @_;
+
+ my $url = $release_data->{'URL'};
+ $release_data->{'URL'} =~ /^(.*)\/([^\/]+)$/;
+ my ($location, $basename) = ($1,$2);
+
+ $installer::logger::Info->printf("downloading %s\n", $basename);
+ $installer::logger::Info->printf(" from '%s'\n", $location);
+ my $filesize = $release_data->{'file-size'};
+ $installer::logger::Info->printf(" expected size is %d\n", $filesize);
+ my $temporary_filename = $filename . ".part";
+ my $resume_size = 0;
+ if ( -f $temporary_filename)
+ {
+ $resume_size = -s $temporary_filename;
+ $installer::logger::Info->printf(" trying to resume at %d/%d bytes\n", $resume_size, $filesize);
+ }
+
+ # Prepare checksum.
+ my $checksum = undef;
+ my $checksum_type = $release_data->{'checksum-type'};
+ my $checksum_value = $release_data->{'checksum-value'};
+ my $digest = undef;
+ if ($checksum_type eq "sha256")
+ {
+ $digest = Digest->new("SHA-256");
+ }
+ elsif ($checksum_type eq "md5")
+ {
+ $digest = Digest->new("md5");
+ }
+ else
+ {
+ installer::logger::PrintError(
+ "checksum type %s is not supported. Supported checksum types are: sha256,md5\n",
+ $checksum_type);
+ return 0;
+ }
+
+ # Download the extension.
+ open my $out, ">>$temporary_filename";
+ binmode($out);
+
+ my $mode = $|;
+ my $handle = select STDOUT;
+ $| = 1;
+ select $handle;
+
+ my $agent = LWP::UserAgent->new();
+ $agent->timeout(120);
+ $agent->show_progress(0);
+ my $last_was_redirect = 0;
+ my $bytes_read = 0;
+ $agent->add_handler('response_redirect'
+ => sub{
+ $last_was_redirect = 1;
+ return;
+ });
+ $agent->add_handler('response_data'
+ => sub{
+ if ($last_was_redirect)
+ {
+ $last_was_redirect = 0;
+ # Throw away the data we got so far.
+ $digest->reset();
+ close $out;
+ open $out, ">$temporary_filename";
+ binmode($out);
+ }
+ my($response,$agent,$h,$data)=@_;
+ print $out $data;
+ $digest->add($data);
+ $bytes_read += length($data);
+ printf("read %*d / %d %d%% \r",
+ length($filesize),
+ $bytes_read,
+ $filesize,
+ $bytes_read*100/$filesize);
+ });
+ my $response;
+ if ($resume_size > 0)
+ {
+ $response = $agent->get($url, 'Range' => "bytes=$resume_size-");
+ }
+ else
+ {
+ $response = $agent->get($url);
+ }
+ close $out;
+
+ $handle = select STDOUT;
+ $| = $mode;
+ select $handle;
+
+ $installer::logger::Info->print(" \r");
+
+ if ($response->is_success())
+ {
+ if ($digest->hexdigest() eq $checksum_value)
+ {
+ $installer::logger::Info->PrintInfo("download was successfull\n");
+ if ( ! rename($temporary_filename, $filename))
+ {
+ installer::logger::PrintError("can not rename '%s' to '%s'\n", $temporary_filename, $filename);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ installer::logger::PrintError("%s checksum is wrong\n", $checksum_type);
+ return 0;
+ }
+ }
+ else
+ {
+ installer::logger::PrintError("there was a download error\n");
+ return 0;
+ }
+}
+
+
+
+
+=head2 ProvideDownloadSet ($version, $language, $package_format)
+
+ Download an installation set when it is not yet present to
+ $ENV{'TARFILE_LOCATION'}. Verify the downloaded file with the
+ checksum that is extracted from the
+ instsetoo_native/data/releases.xml file.
+
+=cut
+sub ProvideDownloadSet ($$$)
+{
+ my ($version, $language, $package_format) = @_;
+
+ my $release_item = installer::patch::ReleasesList::Instance()->{$version}->{$package_format}->{$language};
+
+ # Get basename of installation set from URL.
+ $release_item->{'URL'} =~ /^(.*)\/([^\/]+)$/;
+ my ($location, $basename) = ($1,$2);
+
+ # Is the installation set already present in ext_sources/ ?
+ my $need_download = 0;
+ my $ext_sources_filename = File::Spec->catfile(
+ $ENV{'TARFILE_LOCATION'},
+ $basename);
+ if ( ! -f $ext_sources_filename)
+ {
+ $installer::logger::Info->printf("download set is not in ext_sources/ (%s)\n", $ext_sources_filename);
+ $need_download = 1;
+ }
+ else
+ {
+ $installer::logger::Info->printf("download set exists at '%s'\n", $ext_sources_filename);
+ if ($release_item->{'checksum-type'} eq 'sha256')
+ {
+ $installer::logger::Info->printf("checking SHA256 checksum\n");
+ my $digest = Digest->new("SHA-256");
+ open my $in, "<", $ext_sources_filename;
+ $digest->addfile($in);
+ close $in;
+ if ($digest->hexdigest() ne $release_item->{'checksum-value'})
+ {
+ $installer::logger::Info->printf(" mismatch\n", $ext_sources_filename);
+ $need_download = 1;
+ }
+ else
+ {
+ $installer::logger::Info->printf(" match\n");
+ }
+ }
+ }
+
+ if ($need_download)
+ {
+ if ( ! installer::patch::InstallationSet::Download(
+ $language,
+ $release_item,
+ $ext_sources_filename))
+ {
+ return 0;
+ }
+ if ( ! -f $ext_sources_filename)
+ {
+ $installer::logger::Info->printf("download set could not be downloaded\n");
+ return 0;
+ }
+ }
+
+ return $ext_sources_filename;
+}
+
+1;
diff --git a/solenv/bin/modules/installer/patch/Msi.pm b/solenv/bin/modules/installer/patch/Msi.pm
new file mode 100644
index 000000000000..c5c650a82c47
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/Msi.pm
@@ -0,0 +1,342 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::Msi;
+
+use installer::patch::MsiTable;
+use installer::patch::Tools;
+use strict;
+
+
+=head1 NAME
+
+ package installer::patch::Msi - Class represents a single MSI file and gives access to its tables.
+
+=cut
+
+
+
+=head2 new($class, $version, $language, $product_name)
+
+ Create a new object of the Msi class. The values of $version, $language, and $product_name define
+ where to look for the msi file.
+
+ If construction fails then IsValid() will return false.
+
+=cut
+sub new ($$$$)
+{
+ my ($class, $version, $language, $product_name) = @_;
+
+ my $path = installer::patch::InstallationSet::GetUnpackedMsiPath(
+ $version,
+ $language,
+ "msi",
+ $product_name);
+
+ # Find the msi in the path.
+ my $filename = undef;
+ if ( -d $path)
+ {
+ my @msi_files = glob(File::Spec->catfile($path, "*.msi"));
+ if (scalar @msi_files != 1)
+ {
+ printf STDERR ("there are %d msi files in %s, should be 1", scalar @msi_files, $filename);
+ $filename = "";
+ }
+ else
+ {
+ $filename = $msi_files[0];
+ }
+ }
+ else
+ {
+ installer::logger::PrintError("can not access path '%s' to find msi\n", $path);
+ return undef;
+ }
+
+ if ( ! -f $filename)
+ {
+ installer::logger::PrintError("can not access MSI file at '%s'\n", $filename);
+ return undef;
+ }
+
+ my $self = {
+ 'filename' => $filename,
+ 'path' => $path,
+ 'version' => $version,
+ 'language' => $language,
+ 'package_format' => "msi",
+ 'product_name' => $product_name,
+ 'tmpdir' => File::Temp->newdir(CLEANUP => 1),
+ 'is_valid' => -f $filename
+ };
+ bless($self, $class);
+
+ return $self;
+}
+
+
+
+
+sub IsValid ($)
+{
+ my ($self) = @_;
+
+ return $self->{'is_valid'};
+}
+
+
+
+
+=head2 GetTable($seld, $table_name)
+
+ Return an MsiTable object for $table_name. Table objects are kept
+ alive for the life time of the Msi object. Therefore the second
+ call for the same table is very cheap.
+
+=cut
+sub GetTable ($$)
+{
+ my ($self, $table_name) = @_;
+
+ my $table = $self->{'tables'}->{$table_name};
+ if ( ! defined $table)
+ {
+ my $table_filename = File::Spec->catfile($self->{'tmpdir'}, $table_name .".idt");
+ if ( ! -f $table_filename
+ || ! EnsureAYoungerThanB($table_filename, $self->{'fullname'}))
+ {
+ # Extract table from database to text file on disk.
+ my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name;
+ my $command = join(" ",
+ "msidb.exe",
+ "-d", installer::patch::Tools::CygpathToWindows($self->{'filename'}),
+ "-f", installer::patch::Tools::CygpathToWindows($self->{'tmpdir'}),
+ "-e", $table_name);
+ my $result = qx($command);
+ print $result;
+ }
+
+ # Read table into memory.
+ $table = new installer::patch::MsiTable($table_filename, $table_name);
+ $self->{'tables'}->{$table_name} = $table;
+ }
+
+ return $table;
+}
+
+
+
+
+=head2 EnsureAYoungerThanB ($filename_a, $filename_b)
+
+ Internal function (not a method) that compares to files according
+ to their last modification times (mtime).
+
+=cut
+sub EnsureAYoungerThanB ($$)
+{
+ my ($filename_a, $filename_b) = @_;
+
+ die("file $filename_a does not exist") unless -f $filename_a;
+ die("file $filename_b does not exist") unless -f $filename_b;
+
+ my @stat_a = stat($filename_a);
+ my @stat_b = stat($filename_b);
+
+ if ($stat_a[9] <= $stat_b[9])
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+
+
+=head2 SplitLongShortName($name)
+
+ Split $name (typically from the 'FileName' column in the 'File'
+ table or 'DefaultDir' column in the 'Directory' table) at the '|'
+ into short (8.3) and long names. If there is no '|' in $name then
+ $name is returned as both short and long name.
+
+ Returns long and short name (in this order) as array.
+
+=cut
+sub SplitLongShortName ($)
+{
+ my ($name) = @_;
+
+ if ($name =~ /^([^\|]*)\|(.*)$/)
+ {
+ return ($2,$1);
+ }
+ else
+ {
+ return ($name,$name);
+ }
+}
+
+
+
+=head2 SplitTargetSourceLongShortName ($name)
+
+ Split $name first at the ':' into target and source parts and each
+ of those at the '|'s into long and short parts. Names that follow
+ this pattern come from the 'DefaultDir' column in the 'Directory'
+ table.
+
+=cut
+sub SplitTargetSourceLongShortName ($)
+{
+ my ($name) = @_;
+
+ if ($name =~ /^([^:]*):(.*)$/)
+ {
+ return (installer::patch::Msi::SplitLongShortName($1), installer::patch::Msi::SplitLongShortName($2));
+ }
+ else
+ {
+ my ($long,$short) = installer::patch::Msi::SplitLongShortName($name);
+ return ($long,$short,$long,$short);
+ }
+}
+
+
+
+
+=head2 GetFileToDirectoryMap ($)
+
+ Return a map (hash) that maps the unique name (column 'File' in
+ the 'File' table) to its directory names. Each value is a
+ reference to an array of two elements: the source path and the
+ target path.
+
+ The map is kept alive for the lifetime of the Msi object. All
+ calls but the first are cheap.
+
+=cut
+sub GetFileToDirectoryMap ($)
+{
+ my ($self) = @_;
+
+ if (defined $self->{'FileToDirectoryMap'})
+ {
+ return $self->{'FileToDirectoryMap'};
+ }
+
+ my $file_table = $self->GetTable("File");
+ my $directory_table = $self->GetTable("Directory");
+ my $component_table = $self->GetTable("Component");
+ $installer::logger::Info->printf("got access to tables File, Directory, Component\n");
+
+ my %dir_map = ();
+ foreach my $row (@{$directory_table->GetAllRows()})
+ {
+ my ($target_name, undef, $source_name, undef)
+ = installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir"));
+ $dir_map{$row->GetValue("Directory")} = {
+ 'parent' => $row->GetValue("Directory_Parent"),
+ 'source_name' => $source_name,
+ 'target_name' => $target_name};
+ }
+
+ # Set up full names for all directories.
+ my @todo = map {$_} (keys %dir_map);
+ my $process_count = 0;
+ my $push_count = 0;
+ while (scalar @todo > 0)
+ {
+ ++$process_count;
+
+ my $key = shift @todo;
+ my $item = $dir_map{$key};
+ next if defined $item->{'full_source_name'};
+
+ if ($item->{'parent'} eq "")
+ {
+ # Directory has no parent => full names are the same as the name.
+ $item->{'full_source_name'} = $item->{'source_name'};
+ $item->{'full_target_name'} = $item->{'target_name'};
+ }
+ else
+ {
+ my $parent = $dir_map{$item->{'parent'}};
+ if ( defined $parent->{'full_source_name'})
+ {
+ # Parent aleady has full names => we can create the full name of the current item.
+ $item->{'full_source_name'} = $parent->{'full_source_name'} . "/" . $item->{'source_name'};
+ $item->{'full_target_name'} = $parent->{'full_target_name'} . "/" . $item->{'target_name'};
+ }
+ else
+ {
+ # Parent has to be processed before the current item can be processed.
+ # Push both to the head of the list.
+ unshift @todo, $key;
+ unshift @todo, $item->{'parent'};
+
+ ++$push_count;
+ }
+ }
+ }
+
+ foreach my $key (keys %dir_map)
+ {
+ $dir_map{$key}->{'full_source_name'} =~ s/\/(\.\/)+/\//g;
+ $dir_map{$key}->{'full_source_name'} =~ s/^SourceDir\///;
+ $dir_map{$key}->{'full_target_name'} =~ s/\/(\.\/)+/\//g;
+ $dir_map{$key}->{'full_target_name'} =~ s/^SourceDir\///;
+ }
+ $installer::logger::Info->printf("for %d directories there where %d processing steps and %d pushes\n",
+ $directory_table->GetRowCount(),
+ $process_count,
+ $push_count);
+
+ # Setup a map from component names to directory items.
+ my %component_to_directory_map = map {$_->GetValue('Component') => $_->GetValue('Directory_')} @{$component_table->GetAllRows()};
+
+ # Finally, create the map from files to directories.
+ my $map = {};
+ my $file_component_index = $file_table->GetColumnIndex("Component_");
+ my $file_file_index = $file_table->GetColumnIndex("File");
+ foreach my $file_row (@{$file_table->GetAllRows()})
+ {
+ my $component_name = $file_row->GetValue($file_component_index);
+ my $directory_name = $component_to_directory_map{$component_name};
+ my $dir_item = $dir_map{$directory_name};
+ my $unique_name = $file_row->GetValue($file_file_index);
+ $map->{$unique_name} = [$dir_item->{'full_source_name'},$dir_item->{'full_target_name'}];
+ }
+
+ $installer::logger::Info->printf("got full paths for %d files\n",
+ $file_table->GetRowCount());
+
+ $self->{'FileToDirectoryMap'} = $map;
+ return $map;
+}
+
+
+1;
diff --git a/solenv/bin/modules/installer/patch/MsiRow.pm b/solenv/bin/modules/installer/patch/MsiRow.pm
new file mode 100644
index 000000000000..24a6fd22bc68
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/MsiRow.pm
@@ -0,0 +1,160 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::MsiRow;
+
+=head1 NAME
+
+ package installer::patch::MsiRow - Class that represents a single row of an Msi table.
+
+=cut
+
+
+=head2 new ($class, $table, @data)
+
+ Create a new MsiRow object for the given table row data. Each row
+ stores a reference to its $table so that it can access global
+ values like column names.
+
+=cut
+sub new ($$@)
+{
+ my ($class, $table, @data) = @_;
+
+ my $self = {
+ 'table' => $table,
+ 'values' => [@data]
+ };
+ bless($self, $class);
+
+ my $column_count = $table->GetColumnCount();
+ while (scalar @{$self->{'values'}} < $column_count)
+ {
+ push @{$self->{'values'}}, "";
+ }
+
+ return $self;
+}
+
+
+
+=head2 GetValue($self, $column)
+
+ Return the value in the column specified by $column, which can be
+ either the column name or the index of the column.
+
+=cut
+sub GetValue ($$)
+{
+ my ($self, $column) = @_;
+
+ if ($column =~ /^\d+$/)
+ {
+ return $self->{'values'}->[$column];
+ }
+ else
+ {
+ my $column_index = $self->{'table'}->GetColumnIndex($column);
+ return $self->{'values'}->[$column_index];
+ }
+}
+
+
+
+
+sub SetValue ($$$)
+{
+ my ($self, $column, $value) = @_;
+
+ if ($column =~ /^\d+$/)
+ {
+ $self->{'values'}->[$column] = $value;
+ }
+ else
+ {
+ my $column_index = $self->{'table'}->GetColumnIndex($column);
+ $self->{'values'}->[$column_index] = $value;
+ }
+ $self->{'table'}->MarkAsModified();
+}
+
+
+
+
+sub Format ($$)
+{
+ my $self = shift;
+ my $concatenation = shift;
+
+ my $result = "";
+ my $first = 1;
+ my $index = 0;
+ my $column_count = $self->{'table'}->GetColumnCount();
+ foreach my $item (@{$self->{'values'}})
+ {
+ ++$index;
+
+ if ( ! $first)
+ {
+ $result .= $concatenation;
+ }
+ else
+ {
+ $first = 0;
+ }
+ $result .= $item;
+ }
+ return $result;
+}
+
+
+
+
+sub Clone ($$)
+{
+ my ($self, $new_table) = @_;
+
+ my $clone = { %$self };
+ $clone->{'values'} = [ @{$self->{'values'}} ];
+ $clone->{'table'} = $new_table;
+ bless($clone, "MsiRow");
+
+ return $clone;
+}
+
+
+
+
+sub SetTable ($$)
+{
+ my ($self, $new_table) = @_;
+
+ if (defined $self->{'table'} && $self->{'table'} != $new_table)
+ {
+ MsiTools::Die("can not reset table of row");
+ }
+ else
+ {
+ $self->{'table'} = $new_table;
+ }
+}
+
+1;
diff --git a/solenv/bin/modules/installer/patch/MsiTable.pm b/solenv/bin/modules/installer/patch/MsiTable.pm
new file mode 100644
index 000000000000..a95b94af17bc
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/MsiTable.pm
@@ -0,0 +1,274 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::MsiTable;
+
+=head1 NAME
+
+ package installer::patch::MsiTable - Class that represents one table of an Msi file.
+
+=cut
+
+use installer::patch::MsiRow;
+
+use strict;
+
+=head new ($class, $filename, $table_name)
+
+ Create a new MsiTable object from the output of a previous
+ msidb.exe run. The table is named $table_name, its data is read
+ from $filename.
+
+=cut
+sub new ($$$)
+{
+ my ($class, $filename, $table_name) = @_;
+
+ my $self = {
+ 'name' => $table_name,
+ 'is_valid' => 1
+ };
+ bless($self, $class);
+
+ if ( -f $filename)
+ {
+ $self->ReadFile($filename);
+ }
+ return $self;
+}
+
+
+
+
+sub IsValid ($)
+{
+ my ($self) = @_;
+ return $self->{'is_valid'};
+}
+
+
+
+
+sub Trim ($)
+{
+ my $line = shift;
+
+ $line =~ s/(^\s+|\s+$)//g;
+
+ return $line;
+}
+
+
+
+=head2 ReadFile($self, $filename)
+
+ Read the content of the table from the specified .idt file.
+ For each row a MsiRow object is appended to $self->{'rows'}.
+
+=cut
+sub ReadFile ($$)
+{
+ my ($self, $filename) = @_;
+
+ if ( ! (-f $filename && -r $filename))
+ {
+ printf STDERR ("can not open idt file %s for reading\n", $filename);
+ $self->{'is_valid'} = 0;
+ return;
+ }
+
+ open my $in, "<", $filename;
+
+ my $columns = Trim(<$in>);
+ $self->{'columns'} = [split(/\t/, $columns)];
+
+ my $column_specs = Trim(<$in>);
+ $self->{'column_specs'} = [split(/\t/, $column_specs)];
+
+ # Table name, index columns.
+ my $line = Trim(<$in>);
+ my @items = split(/\t/, $line);
+ if (scalar @items == 3)
+ {
+ $self->{'codepage'} = shift @items;
+ }
+ my $table_name = shift @items;
+ if ($table_name ne $self->{'name'})
+ {
+ printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $table_name);
+ $self->{'is_valid'} = 0;
+ return;
+ }
+ $self->{'index_columns'} = [@items];
+ $self->{'index_column_index'} = $self->GetColumnIndex($items[0]);
+
+ my $rows = [];
+ while (<$in>)
+ {
+ # Remove all trailing returns and newlines. Keep trailing spaces and tabs.
+ s/[\r\n]+$//g;
+
+ my @items = split(/\t/, $_);
+ push @$rows, new installer::patch::MsiRow($self, @items);
+ }
+ $self->{'rows'} = $rows;
+
+ return $self;
+}
+
+
+
+=head2 GetColumnCount($self)
+
+ Return the number of columns in the table.
+
+=cut
+sub GetColumnCount ($)
+{
+ my ($self) = @_;
+
+ return scalar @{$self->{'columns'}};
+}
+
+
+
+
+=head2 GetRowCount($self)
+
+ Return the number of rows in the table.
+
+=cut
+sub GetRowCount ($)
+{
+ my ($self) = @_;
+
+ return scalar @{$self->{'rows'}};
+}
+
+
+
+
+=head2 GetColumnIndx($self, $column_name)
+
+ Return the 0 based index of the column named $column_name. Use
+ this to speed up (slightly) access to column values when accessing
+ many or all rows of a table.
+
+=cut
+sub GetColumnIndex ($$)
+{
+ my ($self, $column_name) = @_;
+
+ my $index = 0;
+ foreach my $name (@{$self->{'columns'}})
+ {
+ if ($name eq $column_name)
+ {
+ return $index;
+ }
+ ++$index;
+ }
+
+ printf STDERR ("did not find column %s in %s\n", $column_name, join(" and ", @{$self->{'columns'}}));
+ return -1;
+}
+
+
+
+
+=head2 GetValue($self, $selector_column, $selector_column_value, $value_column)
+
+ Find the row in which the $selector_column has value
+ $selector_column_value and return its value in the $value_column.
+
+=cut
+
+sub GetValue ($$$$)
+{
+ my ($self, $selector_column, $selector_column_value, $value_column) = @_;
+
+ my $row = $self->GetRow($selector_column, $selector_column_value);
+ if (defined $row)
+ {
+ return $row->GetValue($value_column);
+ }
+ else
+ {
+ return undef;
+ }
+}
+
+
+
+
+=head2 GetRow($self, $column, $value)
+
+ Return the (first) row which has $value in $column.
+
+=cut
+sub GetRow ($$$)
+{
+ my ($self, $column, $value) = @_;
+
+ my $column_index = $self->GetColumnIndex($column);
+ if ($column_index<0)
+ {
+ printf STDERR "ERROR: unknown column $column in table $self->{'name'}\n";
+ return undef;
+ }
+
+ foreach my $row (@{$self->{'rows'}})
+ {
+ if ($row->GetValue($column_index) eq $value)
+ {
+ return $row;
+ }
+ }
+
+ printf STDERR ("ERROR: did not find row for %s->%s in %s\n",
+ $column,
+ $value,
+ table $self->{'name'});
+
+ return undef;
+}
+
+
+
+
+=head2 GetAllRows ($self)
+
+ Return the reference to an array that contains all rows of the table.
+
+=cut
+
+sub GetAllRows ($)
+{
+ my $self = shift;
+
+ return $self->{'rows'};
+}
+
+
+
+
+
+1;
diff --git a/solenv/bin/modules/installer/patch/ReleasesList.pm b/solenv/bin/modules/installer/patch/ReleasesList.pm
new file mode 100644
index 000000000000..320e86400998
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/ReleasesList.pm
@@ -0,0 +1,210 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::ReleasesList;
+
+use XML::LibXML;
+use File::Spec;
+use strict;
+
+=head1 NAME
+
+ package installer::patch::ReleasesList - Functions for accessing the instsetoo_native/data/releases.xml file
+
+=cut
+
+
+my $Instance = undef;
+
+=head2 Instance()
+
+ Return the singleton instance.
+
+=cut
+sub Instance()
+{
+ if ( ! defined $Instance)
+ {
+ $Instance = new installer::patch::ReleasesList();
+ }
+ return $Instance;
+}
+
+
+
+
+=head2 new($class)
+
+ Internal constructor. Don't call.
+
+=cut
+sub new ($)
+{
+ my ($class) = @_;
+
+ my $self = {};
+ bless($self, $class);
+
+ $self->Read();
+
+ return $self;
+}
+
+
+
+
+=head2 GetFirstChild ($node, $child_name)
+
+ Internal function that returns the first child. Use only when the
+ first child is the (expected) only child in a list.
+
+=cut
+sub GetFirstChild ($$)
+{
+ my ($node, $child_name) = @_;
+
+ if ( ! defined $node)
+ {
+ return undef;
+ }
+ else
+ {
+ my @child_nodes = $node->getElementsByTagName($child_name);
+ if (scalar @child_nodes == 0)
+ {
+ return undef;
+ }
+ else
+ {
+ return $child_nodes[0];
+ }
+ }
+}
+
+
+
+
+=head2 GetText ($node)
+
+ Internal function that returns the trimmed text content of a node.
+
+=cut
+sub GetText ($)
+{
+ my ($node) = @_;
+
+ if ( ! defined $node)
+ {
+ return "";
+ }
+ else
+ {
+ my $text = $node->textContent();
+ $text =~ s/(^\s+|\s+$)//g;
+ return $text;
+ }
+}
+
+
+
+
+=head2 Read($self)
+
+ Read the releases.xml file as doctree and parse its content.
+
+=cut
+sub Read ($)
+{
+ my ($self) = @_;
+
+ my $filename = File::Spec->catfile($ENV{'SRC_ROOT'}, "instsetoo_native", "data", "releases.xml");
+ my $parser = XML::LibXML->new();
+ my $document = $parser->parse_file($filename);
+ foreach my $release_node ($document->getElementsByTagName("release"))
+ {
+ my $version_node = GetFirstChild($release_node, "version");
+ my $version = GetText($version_node);
+ next if $version eq "";
+
+ foreach my $download_node (GetFirstChild($release_node, "download"))
+ {
+ my $package_node = GetFirstChild($download_node, "package-format");
+ my $package_format = GetText($package_node);
+ next if $package_format eq "";
+
+ my $download_data = ParseDownloadData($download_node);
+ if (defined $download_data)
+ {
+ $self->{$version}->{$package_format} = $download_data;
+ }
+ }
+ }
+
+}
+
+
+
+
+=head2 ParseDownloadData ($download_node)
+
+ Parse the data for one set of download data (there is one per release and package format).
+
+=cut
+sub ParseDownloadData ($)
+{
+ my ($download_node) = @_;
+
+ my $url_node = GetFirstChild($download_node, "url-template");
+ my $url_template = GetText($url_node);
+ if ($url_template eq "")
+ {
+ print STDERR "releases data file corrupt (no URL template)\n";
+ return undef;
+ }
+
+ my $download_data = {};
+ foreach my $item_node (@{$download_node->getElementsByTagName("item")})
+ {
+ my $language = GetText(GetFirstChild($item_node, "language"));
+ my $checksum_node = GetFirstChild($item_node, "checksum");
+ if ( ! defined $checksum_node)
+ {
+ print STDERR "releases data file corrupt (item has no 'checksum' node)\n";
+ return undef;
+ }
+ my $checksum_type = $checksum_node->getAttribute("type");
+ my $checksum_value = GetText($checksum_node);
+ my $file_size = GetText(GetFirstChild($item_node, "size"));
+
+ my $url = $url_template;
+ $url =~ s/\%L/$language/g;
+ $download_data->{$language} = {
+ 'URL' => $url,
+ 'checksum-type' => $checksum_type,
+ 'checksum-value' => $checksum_value,
+ 'file-size' => $file_size
+ };
+ }
+
+ return $download_data;
+}
+
+1;
diff --git a/solenv/bin/modules/installer/patch/Tools.pm b/solenv/bin/modules/installer/patch/Tools.pm
new file mode 100644
index 000000000000..b29b5596b381
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/Tools.pm
@@ -0,0 +1,47 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::Tools;
+
+=head1 NAME
+
+ package installer::patch::Tools - Collection of functions that don't fit anywhere else
+
+=cut
+
+
+
+
+=head2 CygpathToWindows ($path)
+
+ Convert the given path with the 'cygpath' command into Windows format. Quote backslashes.
+
+=cut
+sub CygpathToWindows($)
+{
+ my ($path) = @_;
+ my $windows_path = qx(cygpath -w "$path");
+ $windows_path =~ s/(^\s+|\s+$)//g;
+ $windows_path =~ s/\\/\\\\/g;
+ return $windows_path;
+}
+
+1;
diff --git a/solenv/bin/modules/installer/patch/Version.pm b/solenv/bin/modules/installer/patch/Version.pm
new file mode 100644
index 000000000000..685df6dc5c58
--- /dev/null
+++ b/solenv/bin/modules/installer/patch/Version.pm
@@ -0,0 +1,74 @@
+#**************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#**************************************************************
+
+package installer::patch::Version;
+
+
+=head1 NAME
+
+ package installer::patch::Version - Functions for handling version numbers.
+
+=cut
+
+
+
+# We handle version numbers that consist of three parts: major, minor and micro version number.
+my $VersionPartCount = 3;
+
+
+
+=head StringToNumberArray($version_string)
+
+ Convert a version string (where the individual parts are separated by '.') into an array of three numbers.
+ Missing numbers are filled with 0.
+
+ Returns an array with three elements (major, minor, micro).
+=cut
+sub StringToNumberArray ($)
+{
+ my ($version_string) = @_;
+
+ my @version_parts = split(/\./, $version_string);
+ while (scalar @version_parts < $VersionPartCount)
+ {
+ push @version_parts, "0";
+ }
+ return @version_parts;
+}
+
+
+
+
+=head ArrayToDirectoryName (@)
+
+ Return a directory name (without any path) for the given array of version numbers.
+
+=cut
+sub ArrayToDirectoryName (@)
+{
+ return "v-".join("-", @_);
+}
+
+
+
+
+
+1;
diff --git a/solenv/bin/modules/installer/scriptitems.pm b/solenv/bin/modules/installer/scriptitems.pm
index d07498bdbafc..127bcff2c876 100644
--- a/solenv/bin/modules/installer/scriptitems.pm
+++ b/solenv/bin/modules/installer/scriptitems.pm
@@ -534,7 +534,7 @@ sub add_bundled_extension_blobs
{
# Add the default extensions for the current language set.
# http:// extensions are taken from ext_sources/.
- for my $name (ExtensionsLst::GetExtensionList("http|https", @installer::globals::languageproducts))
+ for my $name (ExtensionsLst::GetExtensionList("http|https", ($installer::globals::languageproduct)))
{
push @bundle_files, $bundlehttpsrc . $name;
}
@@ -542,11 +542,10 @@ sub add_bundled_extension_blobs
}
$installer::logger::Info->printf(
- "preparing %d extension blob%s for language%s %s:\n",
+ "preparing %d extension blob%s for language %s:\n",
$#bundle_files + 1,
$#bundle_files!=0 ? "s" : "",
- $#installer::globals::languageproducts!=0 ? "s" : "",
- join(" ", @installer::globals::languageproducts));
+ $installer::globals::languageproduct);
foreach my $filename ( @bundle_files)
{
@@ -602,18 +601,17 @@ sub add_bundled_prereg_extensions
else
{
# Add extensions from file:// URLs.
- for my $name (ExtensionsLst::GetExtensionList("file", @installer::globals::languageproducts))
+ for my $name (ExtensionsLst::GetExtensionList("file", ($installer::globals::languageproduct)))
{
push @bundle_files, $name;
}
}
$installer::logger::Info->printf(
- "preparing %d bundled extension%s for language%s %s:\n",
+ "preparing %d bundled extension%s for language %s:\n",
$#bundle_files + 1,
$#bundle_files!=0 ? "s" : "",
- $#installer::globals::languageproducts!=0 ? "s" : "",
- join(" ", @installer::globals::languageproducts));
+ $installer::globals::languageproduct);
foreach my $filename (@bundle_files)
{
$installer::logger::Info->printf(" %s\n", $filename);
@@ -717,12 +715,6 @@ sub set_global_directory_hostnames
$installer::globals::officedirgid = $onedir->{'gid'};
$allvariables->{'OFFICEDIRECTORYHOSTNAME'} = $installer::globals::officedirhostname;
}
- if ( $styles =~ /\bSUNDIRECTORY\b/ )
- {
- $installer::globals::sundirhostname = $onedir->{'HostName'};
- $installer::globals::sundirgid = $onedir->{'gid'};
- $allvariables->{'SUNDIRECTORYHOSTNAME'} = $installer::globals::sundirhostname;
- }
}
}
diff --git a/solenv/bin/modules/installer/windows/component.pm b/solenv/bin/modules/installer/windows/component.pm
index 2804cb5a31a1..f285197cd7cd 100644
--- a/solenv/bin/modules/installer/windows/component.pm
+++ b/solenv/bin/modules/installer/windows/component.pm
@@ -46,11 +46,6 @@ sub get_component_guid
# At this time only a template
my $returnvalue = "\{COMPONENTGUID\}";
- if (( $installer::globals::updatedatabase ) && ( exists($componentidhashref->{$componentname}) ))
- {
- $returnvalue = $componentidhashref->{$componentname};
- }
-
# Returning a ComponentID, that is assigned in scp project
if ( exists($installer::globals::componentid{$componentname}) )
{
diff --git a/solenv/bin/modules/installer/windows/directory.pm b/solenv/bin/modules/installer/windows/directory.pm
index 86be8a214d70..5c0368fb8aa4 100644
--- a/solenv/bin/modules/installer/windows/directory.pm
+++ b/solenv/bin/modules/installer/windows/directory.pm
@@ -269,7 +269,6 @@ sub create_unique_directorynames
if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
$installer::globals::installlocationdirectory = $uniquename;
$installer::globals::installlocationdirectoryset = 1;
- if ( $installer::globals::installlocationdirectory =~ /oracle_/i ) { $installer::globals::sundirexists = 1; }
}
# setting the sundirectory
@@ -358,8 +357,7 @@ sub create_defaultdir_directorynames
my ($directoryref, $shortdirnamehashref) = @_;
my @shortnames = ();
- if ( $installer::globals::updatedatabase ) { @shortnames = values(%{$shortdirnamehashref}); }
- elsif ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
+ if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
{
@@ -371,11 +369,7 @@ sub create_defaultdir_directorynames
# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname); # making program/classes to classes
my $uniquename = $onedir->{'uniquename'};
my $shortstring;
- if (( $installer::globals::updatedatabase ) && ( exists($shortdirnamehashref->{$uniquename}) ))
- {
- $shortstring = $shortdirnamehashref->{$uniquename};
- }
- elsif (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
+ if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
{
$shortstring = $installer::globals::saved83dirmapping{$uniquename};
}
@@ -473,11 +467,6 @@ sub add_root_directories
$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
}
- if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
- {
- $productkey = $productname;
- $realproductkey = $realproductname;
- }
if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
{
$productkey =~ s/\ /\_/g;
diff --git a/solenv/bin/modules/installer/windows/file.pm b/solenv/bin/modules/installer/windows/file.pm
index 00a23d12a2cd..9e0169d052b8 100644
--- a/solenv/bin/modules/installer/windows/file.pm
+++ b/solenv/bin/modules/installer/windows/file.pm
@@ -377,16 +377,7 @@ sub generate_unique_filename_for_filetable
installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$uniquefilename); # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs
# Reading unique filename with help of "Component_" in File table from old database
- if (( $installer::globals::updatedatabase ) && ( exists($uniquefilenamehashref->{"$component/$uniquefilename"}) ))
- {
- $uniquefilename = $uniquefilenamehashref->{"$component/$uniquefilename"}; # syntax of $value: ($uniquename;$shortname)
- if ( $uniquefilename =~ /^\s*(.*?)\;\s*(.*?)\s*$/ ) { $uniquefilename = $1; }
- $lcuniquefilename = lc($uniquefilename);
- $installer::globals::alluniquefilenames{$uniquefilename} = 1;
- $installer::globals::alllcuniquefilenames{$lcuniquefilename} = 1;
- return $uniquefilename;
- }
- elsif (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::savedmapping{"$component/$uniquefilename"}) ))
+ if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::savedmapping{"$component/$uniquefilename"}) ))
{
# If we have a FTK mapping for this component/file, use it.
$installer::globals::savedmapping{"$component/$uniquefilename"} =~ m/^(.*);/;
@@ -473,13 +464,7 @@ sub generate_filename_for_filetable
my $shortstring;
# Reading short string with help of "FileName" in File table from old database
- if (( $installer::globals::updatedatabase ) && ( exists($uniquefilenamehashref->{"$fileref->{'componentname'}/$filename"}) ))
- {
- my $value = $uniquefilenamehashref->{"$fileref->{'componentname'}/$filename"}; # syntax of $value: ($uniquename;$shortname)
- if ( $value =~ /^\s*(.*?)\;\s*(.*?)\s*$/ ) { $shortstring = $2; } # already collected in function "collect_shortnames_from_old_database"
- else { $shortstring = $filename; }
- }
- elsif (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::savedmapping{"$fileref->{'componentname'}/$filename"}) ))
+ if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::savedmapping{"$fileref->{'componentname'}/$filename"}) ))
{
$installer::globals::savedmapping{"$fileref->{'componentname'}/$filename"} =~ m/.*;(.*)/;
if ($1 ne '')
@@ -567,89 +552,6 @@ sub get_fileversion
}
#############################################
-# Returning the sequence for a file
-#############################################
-
-sub get_sequence_for_file
-{
- my ($number, $onefile, $fileentry, $allupdatesequenceshashref, $allupdatecomponentshashref, $allupdatefileorderhashref, $allfilecomponents) = @_;
-
- my $sequence = "";
- my $infoline = "";
- my $pffcomponentname = $onefile->{'componentname'} . "_pff";
-
- if ( $installer::globals::updatedatabase )
- {
- if (( exists($allupdatesequenceshashref->{$onefile->{'uniquename'}}) ) &&
- (( $onefile->{'componentname'} eq $allupdatecomponentshashref->{$onefile->{'uniquename'}} ) ||
- ( $pffcomponentname eq $allupdatecomponentshashref->{$onefile->{'uniquename'}} )))
- {
- # The second condition is necessary to find shifted files, that have same "uniquename", but are now
- # located in another directory. This can be seen at the component name.
- $sequence = $allupdatesequenceshashref->{$onefile->{'uniquename'}};
- $onefile->{'assignedsequencenumber'} = $sequence;
- # Collecting all used sequences, to guarantee, that no number is unused
- $installer::globals::allusedupdatesequences{$sequence} = 1;
- # Special help for files, that already have a "pff" component name (for example after ServicePack 1)
- if ( $pffcomponentname eq $allupdatecomponentshashref->{$onefile->{'uniquename'}} )
- {
- $infoline = "Warning: Special handling for component \"$pffcomponentname\". This file was added after the final, but before this ServicePack.\n";
- $installer::logger::Lang->print($infoline);
- $onefile->{'componentname'} = $pffcomponentname; # pff for "post final file"
- $fileentry->{'Component_'} = $onefile->{'componentname'};
- if ( ! exists($allfilecomponents->{$fileentry->{'Component_'}}) ) { $allfilecomponents->{$fileentry->{'Component_'}} = 1; }
- }
- }
- else
- {
- $installer::globals::updatesequencecounter++;
- $sequence = $installer::globals::updatesequencecounter;
- $onefile->{'assignedsequencenumber'} = $sequence;
- # $onefile->{'assignedcabinetfile'} = $installer::globals::pffcabfilename; # assigning to cabinet file for "post final files"
- # Collecting all new files
- $installer::globals::newupdatefiles{$sequence} = $onefile;
- # Saving in sequence hash
- $allupdatefileorderhashref->{$sequence} = $onefile->{'uniquename'};
-
- # If the new file is part of an existing component, this must be changed now. All files
- # of one component have to be included in one cabinet file. But because the order must
- # not change, all new files have to be added to new components.
- # $onefile->{'componentname'} = $file{'Component_'};
-
- $onefile->{'componentname'} = $onefile->{'componentname'} . "_pff"; # pff for "post final file"
- $fileentry->{'Component_'} = $onefile->{'componentname'};
- if ( ! exists($allfilecomponents->{$fileentry->{'Component_'}}) ) { $allfilecomponents->{$fileentry->{'Component_'}} = 1; }
- $onefile->{'PostFinalFile'} = 1;
- # $installer::globals::pfffileexists = 1;
- # The sequence for this file has changed. It has to be inserted at the end of the files collector.
- $installer::globals::insert_file_at_end = 1;
- $installer::globals::newfilescollector{$sequence} = $onefile; # Adding new files to the end of the filescollector
- $installer::globals::newfilesexist = 1;
- }
- }
- elsif (( $onefile->{'assignedsequencenumber'} ) && ( $installer::globals::use_packages_for_cabs ))
- {
- $sequence = $onefile->{'assignedsequencenumber'};
- }
- else
- {
- $sequence = $number;
- # my $sequence = $number + 1;
-
- # Idea: Each component is packed into a cab file.
- # This requires that all files in one cab file have sequences directly follwing each other,
- # for instance from 1456 to 1466. Then in the media table the LastSequence for this cab file
- # is 1466.
- # Because all files belonging to one component are directly behind each other in the file
- # collector, it is possible to use simply an increasing number as sequence value.
- # If files belonging to one component are not directly behind each other in the files collector
- # this mechanism will no longer work.
- }
-
- return $sequence;
-}
-
-#############################################
# Returning the Windows language of a file
#############################################
@@ -693,91 +595,6 @@ sub generate_registry_keypath
return $keypath;
}
-####################################################################
-# Check, if in an update process files are missing. No removal
-# of files allowed for Windows Patch creation.
-# Also logging all new files, that have to be included in extra
-# components and cab files.
-####################################################################
-
-sub check_file_sequences
-{
- my ($allupdatefileorderhashref, $allupdatecomponentorderhashref) = @_;
-
- # All used sequences stored in %installer::globals::allusedupdatesequences
- # Maximum sequence number of old database stored in $installer::globals::updatelastsequence
- # All new files stored in %installer::globals::newupdatefiles
-
- my $infoline = "";
-
- my @missing_sequences = ();
- my @really_missing_sequences = ();
-
- for ( my $i = 1; $i <= $installer::globals::updatelastsequence; $i++ )
- {
- if ( ! exists($installer::globals::allusedupdatesequences{$i}) ) { push(@missing_sequences, $i); }
- }
-
- if ( $#missing_sequences > -1 )
- {
- # Missing sequences can also be caused by files included in merge modules. This files are added later into the file table.
- # Therefore now it is time to check the content of the merge modules.
-
- for ( my $j = 0; $j <= $#missing_sequences; $j++ )
- {
- my $filename = $allupdatefileorderhashref->{$missing_sequences[$j]};
-
- # Is this a file from a merge module? Then this is no error.
- if ( ! exists($installer::globals::mergemodulefiles{$filename}) )
- {
- push(@really_missing_sequences, $missing_sequences[$j]);
- }
- }
- }
-
- if ( $#really_missing_sequences > -1 )
- {
- my $errorstring = "";
- for ( my $j = 0; $j <= $#really_missing_sequences; $j++ )
- {
- my $filename = $allupdatefileorderhashref->{$really_missing_sequences[$j]};
- my $comp = $allupdatecomponentorderhashref->{$really_missing_sequences[$j]};
- $errorstring = "$errorstring$filename (Sequence: $really_missing_sequences[$j], Component: \"$comp\")\n";
- }
-
- $infoline = "ERROR: Files are removed compared with update database.\nThe following files are missing:\n$errorstring";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program($infoline, "check_file_sequences");
- }
-
- # Searching for new files
-
- my $counter = 0;
-
- foreach my $key ( keys %installer::globals::newupdatefiles )
- {
- my $onefile = $installer::globals::newupdatefiles{$key};
- $counter++;
- if ( $counter == 1 )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->print("New files compared to the update database:\n");
- }
-
- $installer::logger::Lang->printf("%s (%s) Sequence: %s\n",
- $onefile->{'Name'},
- $onefile->{'gid'},
- $onefile->{'assignedsequencenumber'});
- }
-
- if ( $counter == 0 )
- {
- $infoline = "Info: No new file compared with update database!\n";
- $installer::logger::Lang->print($infoline);
- }
-
-}
-
###################################################################
# Collecting further conditions for the component table.
# This is used by multilayer products, to enable installation
@@ -844,7 +661,7 @@ sub collect_shortnames_from_old_database
sub create_files_table
{
- my ($filesref, $allfilecomponentsref, $basedir, $allvariables, $uniquefilenamehashref, $allupdatesequenceshashref, $allupdatecomponentshashref, $allupdatefileorderhashref) = @_;
+ my ($filesref, $allfilecomponentsref, $basedir, $allvariables, $uniquefilenamehashref) = @_;
$installer::logger::Lang->add_timestamp("Performance Info: File Table start");
@@ -869,8 +686,6 @@ sub create_files_table
# my @shortnames = ();
my %shortnames = ();
- if ( $installer::globals::updatedatabase ) { collect_shortnames_from_old_database($uniquefilenamehashref, \%shortnames); }
-
installer::windows::idtglobal::write_idt_header(\@filetable, "file");
installer::windows::idtglobal::write_idt_header(\@filehashtable, "filehash");
@@ -911,7 +726,7 @@ sub create_files_table
$installer::globals::insert_file_at_end = 0;
$counter++;
- $file{'Sequence'} = get_sequence_for_file($counter, $onefile, \%file, $allupdatesequenceshashref, $allupdatecomponentshashref, $allupdatefileorderhashref, \%allfilecomponents);
+ $file{'Sequence'} = $counter;
$onefile->{'sequencenumber'} = $file{'Sequence'};
diff --git a/solenv/bin/modules/installer/windows/media.pm b/solenv/bin/modules/installer/windows/media.pm
index 0dc57b39485e..42c42ae0d6dc 100644
--- a/solenv/bin/modules/installer/windows/media.pm
+++ b/solenv/bin/modules/installer/windows/media.pm
@@ -210,16 +210,7 @@ sub get_last_sequence
{
my ( $cabfilename, $alludpatelastsequences ) = @_;
- my $sequence = 0;
-
- if (( $installer::globals::updatedatabase ) && ( exists($alludpatelastsequences->{$cabfilename}) ))
- {
- $sequence = $alludpatelastsequences->{$cabfilename};
- }
- else
- {
- $sequence = $installer::globals::lastsequence{$cabfilename};
- }
+ my $sequence = $installer::globals::lastsequence{$cabfilename};
return $sequence;
}
@@ -233,7 +224,7 @@ sub get_last_sequence
sub create_media_table
{
- my ($filesref, $basedir, $allvariables, $alludpatelastsequences, $allupdatediskids) = @_;
+ my ($filesref, $basedir, $allvariables) = @_;
my @mediatable = ();
@@ -243,105 +234,7 @@ sub create_media_table
if ( $allvariables->{'INCLUDE_CAB_IN_MSI'} ) { $installer::globals::include_cab_in_msi = 1; }
- if ( $installer::globals::use_packages_for_cabs )
- {
- my $cabfile;
- foreach $cabfile ( sort keys %installer::globals::lastsequence )
- {
- my %media = ();
- $diskid++;
-
- $media{'DiskId'} = get_media_diskid($diskid);
- $media{'LastSequence'} = get_last_sequence($cabfile, $alludpatelastsequences);
- $media{'DiskPrompt'} = get_media_diskprompt();
- $media{'Cabinet'} = get_cabfilename($cabfile);
- $media{'VolumeLabel'} = get_media_volumelabel();
- $media{'Source'} = get_media_source();
-
- my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
- . $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
-
- push(@mediatable, $oneline);
-
- # Comparing the disk id with the disk id from update database. Both have to be identical. New files have to be added
- # to the new pff cabinet file. And existing cab files must not be removed.
- if ( $installer::globals::updatedatabase )
- {
- # Comparing lines in new media table with line from media table in udpate database.
- if ( exists($allupdatediskids->{$media{'Cabinet'}}) )
- {
- if ( $media{'DiskId'} != $allupdatediskids->{$media{'Cabinet'}} )
- {
- installer::exiter::exit_program("ERROR: Different DiskIDs for cab file \"$media{'Cabinet'}\".\nCurrent installation set: \"$media{'DiskId'}\", but update database used \"$allupdatediskids->{$media{'Cabinet'}}\".\nWere cabinet files removed or added?", "create_media_table");
- }
- }
- else
- {
- $installer::logger::Lang->printf(
- "Warning: Could not find cabinet file \"%s}\" in update database. This seems to be an new cabinet file!?\n",
- $media{'Cabinet'});
- }
- }
- }
-
- # one new cabinet file for all files added after the final release
- if (( $installer::globals::updatedatabase ) && ( $installer::globals::pfffileexists ))
- {
- my %media = ();
- $diskid++;
-
- $media{'DiskId'} = get_media_diskid($diskid) + $installer::globals::mergemodulenumber; # Adding mergemodulenumber, because this files are included later
- $media{'LastSequence'} = $installer::globals::updatesequencecounter;
- $media{'DiskPrompt'} = get_media_diskprompt();
- $media{'Cabinet'} = get_cabfilename($installer::globals::pffcabfilename);
- $media{'VolumeLabel'} = get_media_volumelabel();
- $media{'Source'} = get_media_source();
-
- my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
- . $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
-
- push(@mediatable, $oneline);
- }
-
- }
- elsif ( $installer::globals::cab_file_per_component )
- {
- for ( my $i = 0; $i <= $#{$filesref}; $i++ )
- {
- my $onefile = ${$filesref}[$i];
- my $nextfile = ${$filesref}[$i+1];
-
- my $filecomponent = "";
- my $nextcomponent = "";
-
- if ( $onefile->{'componentname'} ) { $filecomponent = $onefile->{'componentname'}; }
- if ( $nextfile->{'componentname'} ) { $nextcomponent = $nextfile->{'componentname'}; }
-
- if ( $filecomponent eq $nextcomponent )
- {
- next; # nothing to do, this is not the last file of a component
- }
-
- my %media = ();
- $diskid++;
-
- $media{'DiskId'} = get_media_diskid($diskid);
- $media{'LastSequence'} = get_media_lastsequence($onefile);
- $media{'DiskPrompt'} = get_media_diskprompt();
- $media{'Cabinet'} = get_media_cabinet($diskid);
- $media{'VolumeLabel'} = get_media_volumelabel();
- $media{'Source'} = get_media_source();
-
- my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
- . $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
-
- push(@mediatable, $oneline);
-
- $media{'Cabinet'} =~ s/^\s*\#//; # removing leading hash
- set_cabinetfilename_for_component_in_file_collector($media{'Cabinet'}, $filesref, $filecomponent, $i);
- }
- }
- elsif ( $installer::globals::fix_number_of_cab_files )
+ if ( $installer::globals::fix_number_of_cab_files )
{
# number of cabfiles
my $maxcabfilenumber = $installer::globals::number_of_cabfiles;
@@ -409,36 +302,6 @@ sub create_media_table
}
}
}
- elsif ( $installer::globals::one_cab_file )
- {
- my %media = ();
- $diskid++;
-
- my $maximumfile = $#{$filesref};
-
- $media{'DiskId'} = get_media_diskid($diskid);
- # $media{'LastSequence'} = ${$filesref}[$maximumfile]->{'sequencenumber'}; # sequence number of the last file
- $media{'LastSequence'} = $maximumfile + 1; # This works also for unsorted file collector
- $media{'DiskPrompt'} = get_media_diskprompt();
- $media{'Cabinet'} = generate_cab_filename($allvariables);
- $media{'VolumeLabel'} = get_media_volumelabel();
- $media{'Source'} = get_media_source();
-
- my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
- . $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
-
- push(@mediatable, $oneline);
-
- # Saving the cabinet file name in the file collector
-
- $media{'Cabinet'} =~ s/^\s*\#//; # removing leading hash
-
- for ( my $i = 0; $i <= $#{$filesref}; $i++ )
- {
- my $onefile = ${$filesref}[$i];
- $onefile->{'cabinet'} = $media{'Cabinet'};
- }
- }
else
{
installer::exiter::exit_program("ERROR: No cab file specification in globals.pm !", "create_media_table");
diff --git a/solenv/bin/modules/installer/windows/mergemodule.pm b/solenv/bin/modules/installer/windows/mergemodule.pm
deleted file mode 100644
index 2ed2781d9747..000000000000
--- a/solenv/bin/modules/installer/windows/mergemodule.pm
+++ /dev/null
@@ -1,1668 +0,0 @@
-#**************************************************************
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#**************************************************************
-
-
-
-package installer::windows::mergemodule;
-
-use Cwd;
-use Digest::MD5;
-use installer::converter;
-use installer::exiter;
-use installer::files;
-use installer::globals;
-use installer::logger;
-use installer::pathanalyzer;
-use installer::remover;
-use installer::scriptitems;
-use installer::systemactions;
-use installer::worker;
-use installer::windows::idtglobal;
-use installer::windows::language;
-
-#################################################################
-# Merging the Windows MergeModules into the msi database.
-#################################################################
-
-sub merge_mergemodules_into_msi_database
-{
- my ($mergemodules, $filesref, $msifilename, $languagestringref, $language, $languagefile, $allvariables, $includepatharrayref, $allupdatesequences, $allupdatelastsequences, $allupdatediskids) = @_;
-
- my $domerge = 0;
- if (( $#{$mergemodules} > -1 ) && ( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack )) { $domerge = 1; }
-
- if ( $domerge )
- {
- installer::logger::include_header_into_logfile("Merging merge modules into msi database");
- $installer::logger::Info->printf("... merging msm files into msi database ... \n");
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: MergeModule into msi database, start");
-
- my $msidb = "msidb.exe"; # Has to be in the path
- my $cabinetfile = "MergeModule.CABinet"; # the name of each cabinet file in a merge file
- my $infoline = "";
- my $systemcall = "";
- my $returnvalue = "";
-
- # 1. Analyzing the MergeModule (has only to be done once)
- # a. -> Extracting cabinet file: msidb.exe -d <msmfile> -x MergeModule.CABinet
- # b. -> Number of files in cabinet file: msidb.exe -d <msmfile> -f <directory> -e File
- # c. -> List of components: msidb.exe -d <msmfile> -f <directory> -e Component
-
- if ( ! $installer::globals::mergemodules_analyzed )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Analyzing MergeModules, start");
- $installer::logger::Lang->print("Analyzing all Merge Modules\n");
- $installer::logger::Lang->print("\n");
-
- %installer::globals::mergemodules = ();
-
- my $mergemoduledir = installer::systemactions::create_directories("mergefiles", $languagestringref);
- # push(@installer::globals::removedirs, $mergemoduledir);
-
- my $mergemodule;
- foreach $mergemodule ( @{$mergemodules} )
- {
- my $filename = $mergemodule->{'Name'};
- my $mergefile = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1);
-
- if ( ! -f $$mergefile ) { installer::exiter::exit_program("ERROR: msm file not found: $filename !", "merge_mergemodules_into_msi_database"); }
- my $completesource = $$mergefile;
-
- my $mergegid = $mergemodule->{'gid'};
- my $workdir = $mergemoduledir . $installer::globals::separator . $mergegid;
- if ( ! -d $workdir ) { installer::systemactions::create_directory($workdir); }
-
- $infoline = "Analyzing Merge Module: $filename\n";
- $installer::logger::Lang->print($infoline);
-
- # copy msm file into working directory
- my $completedest = $workdir . $installer::globals::separator . $filename;
- installer::systemactions::copy_one_file($completesource, $completedest);
- if ( ! -f $completedest ) { installer::exiter::exit_program("ERROR: msm file not found: $completedest !", "merge_mergemodules_into_msi_database"); }
-
- # changing directory
- my $from = cwd();
- my $to = $workdir;
- chdir($to);
-
- # remove an existing cabinet file
- if ( -f $cabinetfile ) { unlink($cabinetfile); }
-
- # exclude cabinet file
- $systemcall = $msidb . " -d " . $filename . " -x " . $cabinetfile;
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not extract cabinet file from merge file: $completedest !", "merge_mergemodules_into_msi_database");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- # exclude tables from mergefile
- # Attention: All listed tables have to exist in the database. If they not exist, an error window pops up
- # and the return value of msidb.exe is not zero. The error window makes it impossible to check the existence
- # of a table with the help of the return value.
- # Solution: Export of all tables by using "*" . Some tables must exist (File Component Directory), other
- # tables do not need to exist (MsiAssembly).
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localworkdir = $workdir;
- $localworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $filename . " -f " . $localworkdir . " -e \\\*";
- }
- else
- {
- # $systemcall = $msidb . " -d " . $filename . " -f " . $workdir . " -e File Component MsiAssembly Directory";
- $systemcall = $msidb . " -d " . $filename . " -f " . $workdir . " -e \*";
- }
-
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not exclude tables from merge file: $completedest !", "merge_mergemodules_into_msi_database");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- # Determining files
- my $idtfilename = "File.idt"; # must exist
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: File \"$idtfilename\" not found in directory \"$workdir\" !", "merge_mergemodules_into_msi_database"); }
- my $filecontent = installer::files::read_file($idtfilename);
- my @file_idt_content = ();
- my $filecounter = 0;
- my %mergefilesequence = ();
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- $filecounter++;
- push(@file_idt_content, ${$filecontent}[$i]);
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.+?)\t(.+?)\t(.+?)\t(.*?)\t(.*?)\t(.*?)\t(\d+?)\s*$/ )
- {
- my $filename = $1;
- my $filesequence = $8;
- $mergefilesequence{$filename} = $filesequence;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "merge_mergemodules_into_msi_database");
- }
- }
-
- # Determining components
- $idtfilename = "Component.idt"; # must exist
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: File \"$idtfilename\" not found in directory \"$workdir\" !", "merge_mergemodules_into_msi_database"); }
- $filecontent = installer::files::read_file($idtfilename);
- my %componentnames = ();
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(\S+)\s+/ ) { $componentnames{$1} = 1; }
- }
-
- # Determining directories
- $idtfilename = "Directory.idt"; # must exist
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: File \"$idtfilename\" not found in directory \"$workdir\" !", "merge_mergemodules_into_msi_database"); }
- $filecontent = installer::files::read_file($idtfilename);
- my %mergedirectories = ();
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(\S+)\s+/ ) { $mergedirectories{$1} = 1; }
- }
-
- # Determining assemblies
- $idtfilename = "MsiAssembly.idt"; # does not need to exist
- my $hasmsiassemblies = 0;
- my %mergeassemblies = ();
- if ( -f $idtfilename )
- {
- $filecontent = installer::files::read_file($idtfilename);
- $hasmsiassemblies = 1;
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(\S+)\s+/ ) { $mergeassemblies{$1} = 1; }
- }
- }
-
- # It is possible, that other tables have to be checked here. This happens, if tables in the
- # merge module have to know the "Feature" or the "Directory", under which the content of the
- # msm file is integrated into the msi database.
-
- # Determining name of cabinet file in installation set
- my $cabfilename = $mergemodule->{'Cabfilename'};
- installer::packagelist::resolve_packagevariables(\$cabfilename, $allvariables, 0);
-
- # Analyzing styles
- # Flag REMOVE_FILE_TABLE is required for msvc9 Merge-Module, because otherwise msidb.exe
- # fails during integration of msm file into msi database.
-
- my $styles = "";
- my $removefiletable = 0;
- if ( $mergemodule->{'Styles'} ) { $styles = $mergemodule->{'Styles'}; }
- if ( $styles =~ /\bREMOVE_FILE_TABLE\b/ ) { $removefiletable = 1; }
-
- if ( $removefiletable )
- {
- my $removeworkdir = $workdir . $installer::globals::separator . "remove_file_idt";
- if ( ! -d $removeworkdir ) { installer::systemactions::create_directory($removeworkdir); }
- my $completeremovedest = $removeworkdir . $installer::globals::separator . $filename;
- installer::systemactions::copy_one_file($completedest, $completeremovedest);
- if ( ! -f $completeremovedest ) { installer::exiter::exit_program("ERROR: msm file not found: $completeremovedest !", "merge_mergemodules_into_msi_database"); }
-
- # Unpacking msm file
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localcompleteremovedest = $completeremovedest;
- my $localremoveworkdir = $removeworkdir;
- $localcompleteremovedest =~ s/\//\\\\/g;
- $localremoveworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localcompleteremovedest . " -f " . $localremoveworkdir . " -e \\\*";
- }
- else
- {
- $systemcall = $msidb . " -d " . $completeremovedest . " -f " . $removeworkdir . " -e \*";
- }
-
- $returnvalue = system($systemcall);
-
- my $idtfilename = $removeworkdir . $installer::globals::separator . "File.idt";
- if ( -f $idtfilename ) { unlink $idtfilename; }
- unlink $completeremovedest;
-
- # Packing msm file without "File.idt"
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localcompleteremovedest = $completeremovedest;
- my $localremoveworkdir = $removeworkdir;
- $localcompleteremovedest =~ s/\//\\\\/g;
- $localremoveworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -c -d " . $localcompleteremovedest . " -f " . $localremoveworkdir . " -i \\\*";
- }
- else
- {
- $systemcall = $msidb . " -c -d " . $completeremovedest . " -f " . $removeworkdir . " -i \*";
- }
- $returnvalue = system($systemcall);
-
- # Using this msm file for merging
- if ( -f $completeremovedest ) { $completedest = $completeremovedest; }
- else { installer::exiter::exit_program("ERROR: Could not find msm file without File.idt: $completeremovedest !", "merge_mergemodules_into_msi_database"); }
- }
-
- # Saving MergeModule info
-
- my %onemergemodulehash = ();
- $onemergemodulehash{'mergefilepath'} = $completedest;
- $onemergemodulehash{'workdir'} = $workdir;
- $onemergemodulehash{'cabinetfile'} = $workdir . $installer::globals::separator . $cabinetfile;
- $onemergemodulehash{'filenumber'} = $filecounter;
- $onemergemodulehash{'componentnames'} = \%componentnames;
- $onemergemodulehash{'cabfilename'} = $cabfilename;
- $onemergemodulehash{'feature'} = $mergemodule->{'Feature'};
- $onemergemodulehash{'rootdir'} = $mergemodule->{'RootDir'};
- $onemergemodulehash{'name'} = $mergemodule->{'Name'};
- $onemergemodulehash{'mergefilesequence'} = \%mergefilesequence;
- $onemergemodulehash{'mergeassemblies'} = \%mergeassemblies;
- $onemergemodulehash{'mergedirectories'} = \%mergedirectories;
- $onemergemodulehash{'hasmsiassemblies'} = $hasmsiassemblies;
- $onemergemodulehash{'removefiletable'} = $removefiletable;
- $onemergemodulehash{'fileidtcontent'} = \@file_idt_content;
-
- $installer::globals::mergemodules{$mergegid} = \%onemergemodulehash;
-
- # Collecting all cab files, to copy them into installation set
- $installer::globals::copy_msm_files{$cabfilename} = $onemergemodulehash{'cabinetfile'};
-
- chdir($from);
- }
-
- $infoline = "All Merge Modules successfully analyzed\n";
- $installer::logger::Lang->print($infoline);
-
- $installer::globals::mergemodules_analyzed = 1;
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Analyzing MergeModules, stop");
-
- $infoline = "\n";
- $installer::logger::Lang->print($infoline);
- }
-
- # 2. Change msi database (has to be done for every msi database -> for every language)
- # a. Merge msm file into msi database: msidb.exe -d <msifile> -m <mergefile>
- # b. Extracting tables from msi database: msidb.exe -d <msifile> -f <directory> -e File Media, ...
- # c. Changing content of msi database in tables: File, Media, Directory, FeatureComponent
- # d. Including tables into msi database: msidb.exe -d <msifile> -f <directory> -i File Media, ...
- # e. Copying cabinet file into installation set (later)
-
- my $counter = 0;
- my $mergemodulegid;
- foreach $mergemodulegid (keys %installer::globals::mergemodules)
- {
- my $mergemodulehash = $installer::globals::mergemodules{$mergemodulegid};
- $counter++;
-
- installer::logger::include_header_into_logfile("Merging Module: $mergemodulehash->{'name'}");
- $installer::logger::Info->printf("\t... %s ... \n", $mergemodulehash->{'name'});
-
- $msifilename = installer::converter::make_path_conform($msifilename);
- my $workdir = $msifilename;
- installer::pathanalyzer::get_path_from_fullqualifiedname(\$workdir);
-
- # changing directory
- my $from = cwd();
- my $to = $workdir;
- chdir($to);
-
- # Saving original msi database
- installer::systemactions::copy_one_file($msifilename, "$msifilename\.$counter");
-
- # Merging msm file, this is the "real" merge command
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Before merging database");
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localmergemodulepath = $mergemodulehash->{'mergefilepath'};
- my $localmsifilename = $msifilename;
- $localmergemodulepath =~ s/\//\\\\/g;
- $localmsifilename =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localmsifilename . " -m " . $localmergemodulepath;
- }
- else
- {
- $systemcall = $msidb . " -d " . $msifilename . " -m " . $mergemodulehash->{'mergefilepath'};
- }
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall . Returnvalue: $returnvalue!\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not merge msm file into database: $mergemodulehash->{'mergefilepath'} !", "merge_mergemodules_into_msi_database");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: After merging database");
-
- # Saving original idt files
- if ( -f "File.idt" ) { installer::systemactions::rename_one_file("File.idt", "File.idt.$counter"); }
- if ( -f "Media.idt" ) { installer::systemactions::rename_one_file("Media.idt", "Media.idt.$counter"); }
- if ( -f "Directory.idt" ) { installer::systemactions::rename_one_file("Directory.idt", "Directory.idt.$counter"); }
- if ( -f "Director.idt" ) { installer::systemactions::rename_one_file("Director.idt", "Director.idt.$counter"); }
- if ( -f "FeatureComponents.idt" ) { installer::systemactions::rename_one_file("FeatureComponents.idt", "FeatureComponents.idt.$counter"); }
- if ( -f "FeatureC.idt" ) { installer::systemactions::rename_one_file("FeatureC.idt", "FeatureC.idt.$counter"); }
- if ( -f "MsiAssembly.idt" ) { installer::systemactions::rename_one_file("MsiAssembly.idt", "MsiAssembly.idt.$counter"); }
- if ( -f "MsiAssem.idt" ) { installer::systemactions::rename_one_file("MsiAssem.idt", "MsiAssem.idt.$counter"); }
-
- # Extracting tables
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Before extracting tables");
-
- my $workingtables = "File Media Directory FeatureComponents"; # required tables
- # Optional tables can be added now
- if ( $mergemodulehash->{'hasmsiassemblies'} ) { $workingtables = $workingtables . " MsiAssembly"; }
-
- # Table "Feature" has to be exported, but it is not necessary to import it.
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localmsifilename = $msifilename;
- my $localworkdir = $workdir;
- $localmsifilename =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localmsifilename . " -f " . $localworkdir . " -e " . "Feature " . $workingtables;
- }
- else
- {
- $systemcall = $msidb . " -d " . $msifilename . " -f " . $workdir . " -e " . "Feature " . $workingtables;
- }
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not exclude tables from msi database: $msifilename !", "merge_mergemodules_into_msi_database");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: After extracting tables");
-
- # Using 8+3 table names, that are used, when tables are integrated into database. The export of tables
- # creates idt-files, that have long names.
-
- if ( -f "Directory.idt" ) { installer::systemactions::rename_one_file("Directory.idt", "Director.idt"); }
- if ( -f "FeatureComponents.idt" ) { installer::systemactions::rename_one_file("FeatureComponents.idt", "FeatureC.idt"); }
- if ( -f "MsiAssembly.idt" ) { installer::systemactions::rename_one_file("MsiAssembly.idt", "MsiAssem.idt"); }
-
- # Changing content of tables: File, Media, Directory, FeatureComponent, MsiAssembly
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing Media table");
- change_media_table($mergemodulehash, $workdir, $mergemodulegid, $allupdatelastsequences, $allupdatediskids);
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing File table");
- $filesref = change_file_table($mergemodulehash, $workdir, $allupdatesequences, $includepatharrayref, $filesref, $mergemodulegid);
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing FeatureComponent table");
- change_featurecomponent_table($mergemodulehash, $workdir);
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing Directory table");
- change_directory_table($mergemodulehash, $workdir);
- if ( $mergemodulehash->{'hasmsiassemblies'} )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing MsiAssembly table");
- change_msiassembly_table($mergemodulehash, $workdir);
- }
-
- # msidb.exe does not merge InstallExecuteSequence, AdminExecuteSequence and AdvtExecuteSequence. Instead it creates
- # new tables ModuleInstallExecuteSequence, ModuleAdminExecuteSequence and ModuleAdvtExecuteSequence that need to be
- # merged into the three ExecuteSequences with the following process (also into InstallUISequence.idt).
-
- # Saving original idt files
- if ( -f "InstallE.idt" ) { installer::systemactions::rename_one_file("InstallE.idt", "InstallE.idt.$counter"); }
- if ( -f "InstallU.idt" ) { installer::systemactions::rename_one_file("InstallU.idt", "InstallU.idt.$counter"); }
- if ( -f "AdminExe.idt" ) { installer::systemactions::rename_one_file("AdminExe.idt", "AdminExe.idt.$counter"); }
- if ( -f "AdvtExec.idt" ) { installer::systemactions::rename_one_file("AdvtExec.idt", "AdvtExec.idt.$counter"); }
- if ( -f "ModuleInstallExecuteSequence.idt" ) { installer::systemactions::rename_one_file("ModuleInstallExecuteSequence.idt", "ModuleInstallExecuteSequence.idt.$counter"); }
- if ( -f "ModuleAdminExecuteSequence.idt" ) { installer::systemactions::rename_one_file("ModuleAdminExecuteSequence.idt", "ModuleAdminExecuteSequence.idt.$counter"); }
- if ( -f "ModuleAdvtExecuteSequence.idt" ) { installer::systemactions::rename_one_file("ModuleAdvtExecuteSequence.idt", "ModuleAdvtExecuteSequence.idt.$counter"); }
-
- # Extracting tables
- my $moduleexecutetables = "ModuleInstallExecuteSequence ModuleAdminExecuteSequence ModuleAdvtExecuteSequence"; # new tables
- my $executetables = "InstallExecuteSequence InstallUISequence AdminExecuteSequence AdvtExecuteSequence"; # tables to be merged
-
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localmsifilename = $msifilename;
- my $localworkdir = $workdir;
- $localmsifilename =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localmsifilename . " -f " . $localworkdir . " -e " . "Feature " . $moduleexecutetables;
- }
- else
- {
- $systemcall = $msidb . " -d " . $msifilename . " -f " . $workdir . " -e " . "Feature " . $moduleexecutetables;
- }
- $returnvalue = system($systemcall);
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localmsifilename = $msifilename;
- my $localworkdir = $workdir;
- $localmsifilename =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localmsifilename . " -f " . $localworkdir . " -e " . "Feature " . $executetables;
- }
- else
- {
- $systemcall = $msidb . " -d " . $msifilename . " -f " . $workdir . " -e " . "Feature " . $executetables;
- }
- $returnvalue = system($systemcall);
-
- # Using 8+3 table names, that are used, when tables are integrated into database. The export of tables
- # creates idt-files, that have long names.
-
- if ( -f "InstallExecuteSequence.idt" ) { installer::systemactions::rename_one_file("InstallExecuteSequence.idt", "InstallE.idt"); }
- if ( -f "InstallUISequence.idt" ) { installer::systemactions::rename_one_file("InstallUISequence.idt", "InstallU.idt"); }
- if ( -f "AdminExecuteSequence.idt" ) { installer::systemactions::rename_one_file("AdminExecuteSequence.idt", "AdminExe.idt"); }
- if ( -f "AdvtExecuteSequence.idt" ) { installer::systemactions::rename_one_file("AdvtExecuteSequence.idt", "AdvtExec.idt"); }
-
- # Merging content of tables ModuleInstallExecuteSequence, ModuleAdminExecuteSequence and ModuleAdvtExecuteSequence
- # into tables InstallExecuteSequence, AdminExecuteSequence and AdvtExecuteSequence
- if ( -f "ModuleInstallExecuteSequence.idt" )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing InstallExecuteSequence table");
- change_executesequence_table($mergemodulehash, $workdir, "InstallE.idt", "ModuleInstallExecuteSequence.idt");
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing InstallUISequence table");
- change_executesequence_table($mergemodulehash, $workdir, "InstallU.idt", "ModuleInstallExecuteSequence.idt");
- }
-
- if ( -f "ModuleAdminExecuteSequence.idt" )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing AdminExecuteSequence table");
- change_executesequence_table($mergemodulehash, $workdir, "AdminExe.idt", "ModuleAdminExecuteSequence.idt");
- }
-
- if ( -f "ModuleAdvtExecuteSequence.idt" )
- {
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Changing AdvtExecuteSequence table");
- change_executesequence_table($mergemodulehash, $workdir, "AdvtExec.idt", "ModuleAdvtExecuteSequence.idt");
- }
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: All tables edited");
-
- # Including tables into msi database
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Before including tables");
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- my $localmsifilename = $msifilename;
- my $localworkdir = $workdir;
- $localmsifilename =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- $systemcall = $msidb . " -d " . $localmsifilename . " -f " . $localworkdir . " -i " . $workingtables. " " . $executetables;
- }
- else
- {
- $systemcall = $msidb . " -d " . $msifilename . " -f " . $workdir . " -i " . $workingtables. " " . $executetables;
- }
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not include tables into msi database: $msifilename !", "merge_mergemodules_into_msi_database");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: After including tables");
-
- chdir($from);
- }
-
- if ( ! $installer::globals::mergefiles_added_into_collector ) { $installer::globals::mergefiles_added_into_collector = 1; } # Now all mergemodules are merged for one language.
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: MergeModule into msi database, stop");
- }
-
- return $filesref;
-}
-
-#########################################################################
-# Analyzing the content of the media table.
-#########################################################################
-
-sub analyze_media_file
-{
- my ($filecontent, $workdir) = @_;
-
- my %filehash = ();
- my $linecount = 0;
- my $counter = 0;
- my $filename = "Media.idt";
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.+?)\t(.+?)\t(.+?)\t(.+?)\t(.*?)\s*$/ )
- {
- my %line = ();
- # Format: DiskId LastSequence DiskPrompt Cabinet VolumeLabel Source
- $line{'DiskId'} = $1;
- $line{'LastSequence'} = $2;
- $line{'DiskPrompt'} = $3;
- $line{'Cabinet'} = $4;
- $line{'VolumeLabel'} = $5;
- $line{'Source'} = $6;
-
- $counter++;
- $filehash{$counter} = \%line;
- }
- else
- {
- $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$filename\" in \"$workdir\" (line $linecount) !", "analyze_media_file");
- }
- }
-
- return \%filehash;
-}
-
-#########################################################################
-# Setting the DiskID for the new cabinet file
-#########################################################################
-
-sub get_diskid
-{
- my ($mediafile, $allupdatediskids, $cabfilename) = @_;
-
- my $diskid = 0;
- my $line;
-
- if (( $installer::globals::updatedatabase ) && ( exists($allupdatediskids->{$cabfilename}) ))
- {
- $diskid = $allupdatediskids->{$cabfilename};
- }
- else
- {
- foreach $line ( keys %{$mediafile} )
- {
- if ( $mediafile->{$line}->{'DiskId'} > $diskid ) { $diskid = $mediafile->{$line}->{'DiskId'}; }
- }
-
- $diskid++;
- }
-
- return $diskid;
-}
-
-#########################################################################
-# Setting the global LastSequence variable
-#########################################################################
-
-sub set_current_last_sequence
-{
- my ($mediafile) = @_;
-
- my $lastsequence = 0;
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( $mediafile->{$line}->{'LastSequence'} > $lastsequence ) { $lastsequence = $mediafile->{$line}->{'LastSequence'}; }
- }
-
- $installer::globals::lastsequence_before_merge = $lastsequence;
-}
-
-#########################################################################
-# Setting the LastSequence for the new cabinet file
-#########################################################################
-
-sub get_lastsequence
-{
- my ($mergemodulehash, $allupdatelastsequences) = @_;
-
- my $lastsequence = 0;
-
- if (( $installer::globals::updatedatabase ) && ( exists($allupdatelastsequences->{$mergemodulehash->{'cabfilename'}}) ))
- {
- $lastsequence = $allupdatelastsequences->{$mergemodulehash->{'cabfilename'}};
- }
- else
- {
- $lastsequence = $installer::globals::lastsequence_before_merge + $mergemodulehash->{'filenumber'};
- }
-
- return $lastsequence;
-}
-
-#########################################################################
-# Setting the DiskPrompt for the new cabinet file
-#########################################################################
-
-sub get_diskprompt
-{
- my ($mediafile) = @_;
-
- my $diskprompt = "";
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( exists($mediafile->{$line}->{'DiskPrompt'}) )
- {
- $diskprompt = $mediafile->{$line}->{'DiskPrompt'};
- last;
- }
- }
-
- return $diskprompt;
-}
-
-#########################################################################
-# Setting the VolumeLabel for the new cabinet file
-#########################################################################
-
-sub get_volumelabel
-{
- my ($mediafile) = @_;
-
- my $volumelabel = "";
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( exists($mediafile->{$line}->{'VolumeLabel'}) )
- {
- $volumelabel = $mediafile->{$line}->{'VolumeLabel'};
- last;
- }
- }
-
- return $volumelabel;
-}
-
-#########################################################################
-# Setting the Source for the new cabinet file
-#########################################################################
-
-sub get_source
-{
- my ($mediafile) = @_;
-
- my $source = "";
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( exists($mediafile->{$line}->{'Source'}) )
- {
- $diskprompt = $mediafile->{$line}->{'Source'};
- last;
- }
- }
-
- return $source;
-}
-
-#########################################################################
-# For each Merge Module one new line has to be included into the
-# media table.
-#########################################################################
-
-sub create_new_media_line
-{
- my ($mergemodulehash, $mediafile, $allupdatelastsequences, $allupdatediskids) = @_;
-
- my $diskid = get_diskid($mediafile, $allupdatediskids, $mergemodulehash->{'cabfilename'});
- my $lastsequence = get_lastsequence($mergemodulehash, $allupdatelastsequences);
- my $diskprompt = get_diskprompt($mediafile);
- my $cabinet = $mergemodulehash->{'cabfilename'};
- my $volumelabel = get_volumelabel($mediafile);
- my $source = get_source($mediafile);
-
- if ( $installer::globals::include_cab_in_msi ) { $cabinet = "\#" . $cabinet; }
-
- my $newline = "$diskid\t$lastsequence\t$diskprompt\t$cabinet\t$volumelabel\t$source\n";
-
- return $newline;
-}
-
-#########################################################################
-# Setting the last diskid in media table.
-#########################################################################
-
-sub get_last_diskid
-{
- my ($mediafile) = @_;
-
- my $lastdiskid = 0;
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( $mediafile->{$line}->{'DiskId'} > $lastdiskid ) { $lastdiskid = $mediafile->{$line}->{'DiskId'}; }
- }
-
- return $lastdiskid;
-}
-
-#########################################################################
-# Setting global variable for last cab file name.
-#########################################################################
-
-sub set_last_cabfile_name
-{
- my ($mediafile, $lastdiskid) = @_;
-
- my $line;
- foreach $line ( keys %{$mediafile} )
- {
- if ( $mediafile->{$line}->{'DiskId'} == $lastdiskid ) { $installer::globals::lastcabfilename = $mediafile->{$line}->{'Cabinet'}; }
- }
- my $infoline = "Setting last cabinet file: $installer::globals::lastcabfilename\n";
- $installer::logger::Lang->print($infoline);
-}
-
-#########################################################################
-# In the media table the new cabinet file has to be added or the
-# number of the last cabinet file has to be increased.
-#########################################################################
-
-sub change_media_table
-{
- my ( $mergemodulehash, $workdir, $mergemodulegid, $allupdatelastsequences, $allupdatediskids ) = @_;
-
- my $infoline = "Changing content of table \"Media\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = "Media.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" in \"$workdir\" !", "change_media_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my $mediafile = analyze_media_file($filecontent, $workdir);
- set_current_last_sequence($mediafile);
-
- if ( $installer::globals::fix_number_of_cab_files )
- {
- # Determining the line with the highest sequencenumber. That file needs to be updated.
- my $lastdiskid = get_last_diskid($mediafile);
- if ( $installer::globals::lastcabfilename eq "" ) { set_last_cabfile_name($mediafile, $lastdiskid); }
- my $newmaxsequencenumber = $installer::globals::lastsequence_before_merge + $mergemodulehash->{'filenumber'};
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(\Q$lastdiskid\E\t)\Q$installer::globals::lastsequence_before_merge\E(\t.*)$/ )
- {
- my $start = $1;
- my $final = $2;
- $infoline = "Merge: Old line in media table: ${$filecontent}[$i]\n";
- $installer::logger::Lang->print($infoline);
- my $newline = $start . $newmaxsequencenumber . $final . "\n";
- ${$filecontent}[$i] = $newline;
- $infoline = "Merge: Changed line in media table: ${$filecontent}[$i]\n";
- $installer::logger::Lang->print($infoline);
- }
- }
- }
- else
- {
- # the new line is identical for all localized databases, but has to be created for each MergeModule ($mergemodulegid)
- if ( ! exists($installer::globals::merge_media_line{$mergemodulegid}) )
- {
- $installer::globals::merge_media_line{$mergemodulegid} = create_new_media_line($mergemodulehash, $mediafile, $allupdatelastsequences, $allupdatediskids);
- }
-
- $infoline = "Adding line: $installer::globals::merge_media_line{$mergemodulegid}\n";
- $installer::logger::Lang->print($infoline);
-
- # adding new line
- push(@{$filecontent}, $installer::globals::merge_media_line{$mergemodulegid});
- }
-
- # saving file
- installer::files::save_file($filename, $filecontent);
-}
-
-#########################################################################
-# Putting the directory table content into a hash.
-#########################################################################
-
-sub analyze_directorytable_file
-{
- my ($filecontent, $idtfilename) = @_;
-
- my %dirhash = ();
- # Iterating over the file content
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.*?)\t(.*?)\s*$/ )
- {
- my %line = ();
- # Format: Directory Directory_Parent DefaultDir
- $line{'Directory'} = $1;
- $line{'Directory_Parent'} = $2;
- $line{'DefaultDir'} = $3;
- $line{'linenumber'} = $i; # saving also the line number for direct access
-
- my $uniquekey = $line{'Directory'};
- $dirhash{$uniquekey} = \%line;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "analyze_directorytable_file");
- }
- }
-
- return \%dirhash;
-}
-
-#########################################################################
-# Putting the msi assembly table content into a hash.
-#########################################################################
-
-sub analyze_msiassemblytable_file
-{
- my ($filecontent, $idtfilename) = @_;
-
- my %assemblyhash = ();
- # Iterating over the file content
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.+?)\t(.+?)\t(.*?)\t(.*?)\s*$/ )
- {
- my %line = ();
- # Format: Component_ Feature_ File_Manifest File_Application Attributes
- $line{'Component'} = $1;
- $line{'Feature'} = $2;
- $line{'File_Manifest'} = $3;
- $line{'File_Application'} = $4;
- $line{'Attributes'} = $5;
- $line{'linenumber'} = $i; # saving also the line number for direct access
-
- my $uniquekey = $line{'Component'};
- $assemblyhash{$uniquekey} = \%line;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "analyze_msiassemblytable_file");
- }
- }
-
- return \%assemblyhash;
-}
-
-#########################################################################
-# Putting the file table content into a hash.
-#########################################################################
-
-sub analyze_filetable_file
-{
- my ( $filecontent, $idtfilename ) = @_;
-
- my %filehash = ();
- # Iterating over the file content
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.+?)\t(.+?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.+?)\s*$/ )
- {
- my %line = ();
- # Format: File Component_ FileName FileSize Version Language Attributes Sequence
- $line{'File'} = $1;
- $line{'Component'} = $2;
- $line{'FileName'} = $3;
- $line{'FileSize'} = $4;
- $line{'Version'} = $5;
- $line{'Language'} = $6;
- $line{'Attributes'} = $7;
- $line{'Sequence'} = $8;
- $line{'linenumber'} = $i; # saving also the line number for direct access
-
- my $uniquekey = $line{'File'};
- $filehash{$uniquekey} = \%line;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "analyze_filetable_file");
- }
- }
-
- return \%filehash;
-}
-
-#########################################################################
-# Creating a new line for the directory table.
-#########################################################################
-
-sub get_new_line_for_directory_table
-{
- my ($dir) = @_;
-
- my $newline = "$dir->{'Directory'}\t$dir->{'Directory_Parent'}\t$dir->{'DefaultDir'}\n";
-
- return $newline;
-}
-
-#########################################################################
-# Creating a new line for the file table.
-#########################################################################
-
-sub get_new_line_for_file_table
-{
- my ($file) = @_;
-
- my $newline = "$file->{'File'}\t$file->{'Component'}\t$file->{'FileName'}\t$file->{'FileSize'}\t$file->{'Version'}\t$file->{'Language'}\t$file->{'Attributes'}\t$file->{'Sequence'}\n";
-
- return $newline;
-}
-
-#########################################################################
-# Creating a new line for the msiassembly table.
-#########################################################################
-
-sub get_new_line_for_msiassembly_table
-{
- my ($assembly) = @_;
-
- my $newline = "$assembly->{'Component'}\t$assembly->{'Feature'}\t$assembly->{'File_Manifest'}\t$assembly->{'File_Application'}\t$assembly->{'Attributes'}\n";
-
- return $newline;
-}
-
-#########################################################################
-# Sorting the files collector, if there are files, following
-# the merge module files.
-#########################################################################
-
-sub sort_files_collector_for_sequence
-{
- my ($filesref) = @_;
-
- my @sortarray = ();
- my %helphash = ();
-
- for ( my $i = 0; $i <= $#{$filesref}; $i++ )
- {
- my $onefile = ${$filesref}[$i];
- if ( ! exists($onefile->{'sequencenumber'}) ) { installer::exiter::exit_program("ERROR: Could not find sequencenumber for file: $onefile->{'uniquename'} !", "sort_files_collector_for_sequence"); }
- my $sequence = $onefile->{'sequencenumber'};
- $helphash{$sequence} = $onefile;
- }
-
- foreach my $seq ( sort { $a <=> $b } keys %helphash ) { push(@sortarray, $helphash{$seq}); }
-
- return \@sortarray;
-}
-
-#########################################################################
-# In the file table "Sequence" and "Attributes" have to be changed.
-#########################################################################
-
-sub change_file_table
-{
- my ($mergemodulehash, $workdir, $allupdatesequenceshashref, $includepatharrayref, $filesref, $mergemodulegid) = @_;
-
- my $infoline = "Changing content of table \"File\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $idtfilename = "File.idt";
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "change_file_table"); }
-
- my $filecontent = installer::files::read_file($idtfilename);
-
- # If File.idt needed to be removed before the msm database was merged into the msi database,
- # now it is time to add the content into File.idt
- if ( $mergemodulehash->{'removefiletable'} )
- {
- for ( my $i = 0; $i <= $#{$mergemodulehash->{'fileidtcontent'}}; $i++ )
- {
- push(@{$filecontent}, ${$mergemodulehash->{'fileidtcontent'}}[$i]);
- }
- }
-
- # Unpacking the MergeModule.CABinet (only once)
- # Unpacking into temp directory. Warning: expand.exe has problems with very long unpack directories.
-
- my $unpackdir = installer::systemactions::create_directories("cab", "");
- push(@installer::globals::removedirs, $unpackdir);
- $unpackdir = $unpackdir . $installer::globals::separator . $mergemodulegid;
-
- my %newfileshash = ();
- if (( $installer::globals::fix_number_of_cab_files ) && ( ! $installer::globals::mergefiles_added_into_collector ))
- {
- if ( ! -d $unpackdir ) { installer::systemactions::create_directory($unpackdir); }
-
- # Unpack the cab file, so that in can be included into the last office cabinet file. Attention: cararc.exe from cabsdk required.
- # cabarc.exe -o X <fullcabfilepath>
-
- # my $cabarcfilename = "cabarc.exe";
- # my $cabarcfile = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$cabarcfilename, $includepatharrayref, 1);
-
- # if ( ! -f $$cabarcfile )
- # {
- # $cabarcfilename = "CABARC.EXE";
- # $cabarcfile = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$cabarcfilename, $includepatharrayref, 1);
- # if ( ! -f $$cabarcfile )
- # {
- # installer::exiter::exit_program("ERROR: cabarc.exe not found !", "change_file_table");
- # }
- # }
- # my $cabarc = $$cabarcfile;
-
- # changing directory
- my $from = cwd();
- my $to = $mergemodulehash->{'workdir'};
- if ( $^O =~ /cygwin/i ) {
- $to = qx(cygpath -u "$to");
- chomp $to;
- }
-
- chdir($to) || die "Could not chdir to \"$to\"\n";
-
- # Unpack the cab file, so that in can be included into the last office cabinet file.
- # Not using cabarc.exe from cabsdk for unpacking cabinet files, but "expand.exe" that
- # should be available on every Windows system.
-
- $infoline = "Unpacking cabinet file: $mergemodulehash->{'cabinetfile'}\n";
- $installer::logger::Lang->print($infoline);
-
- # Avoid the Cygwin expand command
- my $expandfile = "expand.exe"; # Has to be in the path
- if ( $^O =~ /cygwin/i ) {
- $expandfile = qx(cygpath -u "$ENV{WINDIR}"/System32/expand.exe);
- chomp $expandfile;
- }
-
- my $cabfilename = "MergeModule.CABinet";
-
- # exclude cabinet file
- # my $systemcall = $cabarc . " -o X " . $mergemodulehash->{'cabinetfile'};
-
- my $systemcall = "";
- if ( $^O =~ /cygwin/i ) {
- my $localunpackdir = qx(cygpath -m "$unpackdir");
- chomp $localunpackdir;
- $systemcall = $expandfile . " " . $cabfilename . " -F:\\\* " . $localunpackdir;
- }
- else
- {
- $systemcall = $expandfile . " " . $cabfilename . " -F:\* " . $unpackdir . " 2\>\&1";
- }
-
- my $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not extract cabinet file: $mergemodulehash->{'cabinetfile'} !", "change_file_table");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- chdir($from);
- }
-
- # For performance reasons creating a hash with file names and rows
- # The content of File.idt is changed after every merge -> content cannot be saved in global hash
- $merge_filetablehashref = analyze_filetable_file($filecontent, $idtfilename);
-
- my $attributes = "16384"; # Always
-
- my $filename;
- foreach $filename (keys %{$mergemodulehash->{'mergefilesequence'}} )
- {
- my $mergefilesequence = $mergemodulehash->{'mergefilesequence'}->{$filename};
-
- if ( ! exists($merge_filetablehashref->{$filename}) ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" in \"$idtfilename\" !", "change_file_table"); }
- my $filehash = $merge_filetablehashref->{$filename};
- my $linenumber = $filehash->{'linenumber'};
-
- # <- this line has to be changed concerning "Sequence" and "Attributes"
- $filehash->{'Attributes'} = $attributes;
-
- # If this is an update process, the sequence numbers have to be reused.
- if ( $installer::globals::updatedatabase )
- {
- if ( ! exists($allupdatesequenceshashref->{$filehash->{'File'}}) ) { installer::exiter::exit_program("ERROR: Sequence not defined for file \"$filehash->{'File'}\" !", "change_file_table"); }
- $filehash->{'Sequence'} = $allupdatesequenceshashref->{$filehash->{'File'}};
- # Saving all mergemodule sequence numbers. This is important for creating ddf files
- $installer::globals::allmergemodulefilesequences{$filehash->{'Sequence'}} = 1;
- }
- else
- {
- # Important saved data: $installer::globals::lastsequence_before_merge.
- # This mechanism keeps the correct order inside the new cabinet file.
- $filehash->{'Sequence'} = $filehash->{'Sequence'} + $installer::globals::lastsequence_before_merge;
- }
-
- my $oldline = ${$filecontent}[$linenumber];
- my $newline = get_new_line_for_file_table($filehash);
- ${$filecontent}[$linenumber] = $newline;
-
- $infoline = "Merge, replacing line:\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "Old: $oldline\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "New: $newline\n";
- $installer::logger::Lang->print($infoline);
-
- # Adding files to the files collector (but only once)
- if (( $installer::globals::fix_number_of_cab_files ) && ( ! $installer::globals::mergefiles_added_into_collector ))
- {
- # If the number of cabinet files is kept constant,
- # all files from the mergemodule cabinet files will
- # be integrated into the last office cabinet file
- # (installer::globals::lastcabfilename).
- # Therefore the files must now be added to the filescollector,
- # so that they will be integrated into the ddf files.
-
- # Problem with very long filenames -> copying to shorter filenames
- my $newfilename = "f" . $filehash->{'Sequence'};
- my $completesource = $unpackdir . $installer::globals::separator . $filehash->{'File'};
- my $completedest = $unpackdir . $installer::globals::separator . $newfilename;
- installer::systemactions::copy_one_file($completesource, $completedest);
-
- my $locallastcabfilename = $installer::globals::lastcabfilename;
- if ( $locallastcabfilename =~ /^\s*\#/ ) { $locallastcabfilename =~ s/^\s*\#//; } # removing beginning hashes
-
- # Create new file hash for file collector
- my %newfile = ();
- $newfile{'sequencenumber'} = $filehash->{'Sequence'};
- $newfile{'assignedsequencenumber'} = $filehash->{'Sequence'};
- $newfile{'cabinet'} = $locallastcabfilename;
- $newfile{'sourcepath'} = $completedest;
- $newfile{'componentname'} = $filehash->{'Component'};
- $newfile{'uniquename'} = $filehash->{'File'};
- $newfile{'Name'} = $filehash->{'File'};
-
- # Saving in globals sequence hash
- $installer::globals::uniquefilenamesequence{$filehash->{'File'}} = $filehash->{'Sequence'};
-
- if ( ! -f $newfile{'sourcepath'} ) { installer::exiter::exit_program("ERROR: File \"$newfile{'sourcepath'}\" must exist!", "change_file_table"); }
-
- # Collecting all new files. Attention: This files must be included into files collector in correct order!
- $newfileshash{$filehash->{'Sequence'}} = \%newfile;
- # push(@{$filesref}, \%newfile); -> this is not the correct order
- }
- }
-
- # Now the files can be added to the files collector
- # In the case of an update process, there can be new files, that have to be added after the merge module files.
- # Warning: In multilingual installation sets, the files only have to be added once to the files collector!
-
- if ( ! $installer::globals::mergefiles_added_into_collector )
- {
- foreach my $localsequence ( sort { $a <=> $b } keys %newfileshash ) { push(@{$filesref}, $newfileshash{$localsequence}); }
- if ( $installer::globals::newfilesexist ) { $filesref = sort_files_collector_for_sequence($filesref); }
- # $installer::globals::mergefiles_added_into_collector = 1; -> Not yet. Only if all mergemodules are merged for one language.
- }
-
- # Saving the idt file (for every language)
- installer::files::save_file($idtfilename, $filecontent);
-
- return $filesref;
-}
-
-#########################################################################
-# Reading the file "Director.idt". The Directory, that is defined in scp
-# has to be defined in this table.
-#########################################################################
-
-sub collect_directories
-{
- my $idtfilename = "Director.idt";
- my $filecontent = installer::files::read_file($idtfilename);
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- # Format: Directory Directory_Parent DefaultDir
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.*?)\t(.*?)\s*$/ )
- {
- $installer::globals::merge_alldirectory_hash{$1} = 1;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "collect_directories");
- }
- }
-}
-
-#########################################################################
-# Reading the file "Feature.idt". The Feature, that is defined in scp
-# has to be defined in this table.
-#########################################################################
-
-sub collect_feature
-{
- my $idtfilename = "Feature.idt";
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "collect_feature"); }
- my $filecontent = installer::files::read_file($idtfilename);
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- # Format: Feature Feature_Parent Title Description Display Level Directory_ Attributes
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
- {
- $installer::globals::merge_allfeature_hash{$1} = 1;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "collect_feature");
- }
- }
-}
-
-#########################################################################
-# In the featurecomponent table, the new connections have to be added.
-#########################################################################
-
-sub change_featurecomponent_table
-{
- my ($mergemodulehash, $workdir) = @_;
-
- my $infoline = "Changing content of table \"FeatureComponents\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $idtfilename = "FeatureC.idt";
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "change_featurecomponent_table"); }
-
- my $filecontent = installer::files::read_file($idtfilename);
-
- # Simply adding for each new component one line. The Feature has to be defined in scp project.
- my $feature = $mergemodulehash->{'feature'};
-
- if ( ! $installer::globals::mergefeaturecollected )
- {
- collect_feature(); # putting content into hash %installer::globals::merge_allfeature_hash
- $installer::globals::mergefeaturecollected = 1;
- }
-
- if ( ! exists($installer::globals::merge_allfeature_hash{$feature}) )
- {
- installer::exiter::exit_program("ERROR: Unknown feature defined in scp: \"$feature\" . Not defined in table \"Feature\" !", "change_featurecomponent_table");
- }
-
- my $component;
- foreach $component ( keys %{$mergemodulehash->{'componentnames'}} )
- {
- my $line = "$feature\t$component\n";
- push(@{$filecontent}, $line);
- $infoline = "Adding line: $line\n";
- $installer::logger::Lang->print($infoline);
- }
-
- # saving file
- installer::files::save_file($idtfilename, $filecontent);
-}
-
-#########################################################################
-# In the directory table, the directory parent has to be changed,
-# if it is not TARGETDIR.
-#########################################################################
-
-sub change_directory_table
-{
- my ($mergemodulehash, $workdir) = @_;
-
- # directory for MergeModule has to be defined in scp project
- my $scpdirectory = $mergemodulehash->{'rootdir'};
-
- if ( $scpdirectory ne "TARGETDIR" ) # TARGETDIR works fine, when using msidb.exe
- {
- my $infoline = "Changing content of table \"Directory\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $idtfilename = "Director.idt";
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "change_directory_table"); }
-
- my $filecontent = installer::files::read_file($idtfilename);
-
- if ( ! $installer::globals::mergedirectoriescollected )
- {
- collect_directories(); # putting content into %installer::globals::merge_alldirectory_hash, only first column!
- $installer::globals::mergedirectoriescollected = 1;
- }
-
- if ( ! exists($installer::globals::merge_alldirectory_hash{$scpdirectory}) )
- {
- installer::exiter::exit_program("ERROR: Unknown directory defined in scp: \"$scpdirectory\" . Not defined in table \"Directory\" !", "change_directory_table");
- }
-
- # If the definition in scp is okay, now the complete content of "Director.idt" can be analyzed
- my $merge_directorytablehashref = analyze_directorytable_file($filecontent, $idtfilename);
-
- my $directory;
- foreach $directory (keys %{$mergemodulehash->{'mergedirectories'}} )
- {
- if ( ! exists($merge_directorytablehashref->{$directory}) ) { installer::exiter::exit_program("ERROR: Could not find directory \"$directory\" in \"$idtfilename\" !", "change_directory_table"); }
- my $dirhash = $merge_directorytablehashref->{$directory};
- my $linenumber = $dirhash->{'linenumber'};
-
- # <- this line has to be changed concerning "Directory_Parent",
- # if the current value is "TARGETDIR", which is the default value from msidb.exe
-
- if ( $dirhash->{'Directory_Parent'} eq "TARGETDIR" )
- {
- $dirhash->{'Directory_Parent'} = $scpdirectory;
-
- my $oldline = ${$filecontent}[$linenumber];
- my $newline = get_new_line_for_directory_table($dirhash);
- ${$filecontent}[$linenumber] = $newline;
-
- $infoline = "Merge, replacing line:\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "Old: $oldline\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "New: $newline\n";
- $installer::logger::Lang->print($infoline);
- }
- }
-
- # saving file
- installer::files::save_file($idtfilename, $filecontent);
- }
-}
-
-#########################################################################
-# In the msiassembly table, the feature has to be changed.
-#########################################################################
-
-sub change_msiassembly_table
-{
- my ($mergemodulehash, $workdir) = @_;
-
- my $infoline = "Changing content of table \"MsiAssembly\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $idtfilename = "MsiAssem.idt";
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "change_msiassembly_table"); }
-
- my $filecontent = installer::files::read_file($idtfilename);
-
- # feature has to be defined in scp project
- my $feature = $mergemodulehash->{'feature'};
-
- if ( ! $installer::globals::mergefeaturecollected )
- {
- collect_feature(); # putting content into hash %installer::globals::merge_allfeature_hash
- $installer::globals::mergefeaturecollected = 1;
- }
-
- if ( ! exists($installer::globals::merge_allfeature_hash{$feature}) )
- {
- installer::exiter::exit_program("ERROR: Unknown feature defined in scp: \"$feature\" . Not defined in table \"Feature\" !", "change_msiassembly_table");
- }
-
- my $merge_msiassemblytablehashref = analyze_msiassemblytable_file($filecontent, $idtfilename);
-
- my $component;
- foreach $component (keys %{$mergemodulehash->{'mergeassemblies'}} )
- {
- if ( ! exists($merge_msiassemblytablehashref->{$component}) ) { installer::exiter::exit_program("ERROR: Could not find component \"$component\" in \"$idtfilename\" !", "change_msiassembly_table"); }
- my $assemblyhash = $merge_msiassemblytablehashref->{$component};
- my $linenumber = $assemblyhash->{'linenumber'};
-
- # <- this line has to be changed concerning "Feature"
- $assemblyhash->{'Feature'} = $feature;
-
- my $oldline = ${$filecontent}[$linenumber];
- my $newline = get_new_line_for_msiassembly_table($assemblyhash);
- ${$filecontent}[$linenumber] = $newline;
-
- $infoline = "Merge, replacing line:\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "Old: $oldline\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "New: $newline\n";
- $installer::logger::Lang->print($infoline);
- }
-
- # saving file
- installer::files::save_file($idtfilename, $filecontent);
-}
-
-#########################################################################
-# Creating file content hash
-#########################################################################
-
-sub make_executeidtcontent_hash
-{
- my ($filecontent, $idtfilename) = @_;
-
- my %newhash = ();
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- # Format for all sequence tables: Action Condition Sequence
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.*?)\t(.*?)\s*$/ )
- {
- my %onehash = ();
- $onehash{'Action'} = $1;
- $onehash{'Condition'} = $2;
- $onehash{'Sequence'} = $3;
- $newhash{$onehash{'Action'}} = \%onehash;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "make_executeidtcontent_hash");
- }
- }
-
- return \%newhash;
-}
-
-#########################################################################
-# Creating file content hash
-#########################################################################
-
-sub make_moduleexecuteidtcontent_hash
-{
- my ($filecontent, $idtfilename) = @_;
-
- my %newhash = ();
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( $i <= 2 ) { next; } # ignoring first three lines
- if ( ${$filecontent}[$i] =~ /^\s*$/ ) { next; } # ignoring empty lines
- # Format for all module sequence tables: Action Sequence BaseAction After Condition
- if ( ${$filecontent}[$i] =~ /^\s*(.+?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
- {
- my %onehash = ();
- $onehash{'Action'} = $1;
- $onehash{'Sequence'} = $2;
- $onehash{'BaseAction'} = $3;
- $onehash{'After'} = $4;
- $onehash{'Condition'} = $5;
- $newhash{$onehash{'Action'}} = \%onehash;
- }
- else
- {
- my $linecount = $i + 1;
- installer::exiter::exit_program("ERROR: Unknown line format in table \"$idtfilename\" (line $linecount) !", "make_executeidtcontent_hash");
- }
- }
-
- return \%newhash;
-}
-
-#########################################################################
-# ExecuteSequence tables need to be merged with
-# ModuleExecuteSequence tables created by msidb.exe.
-#########################################################################
-
-sub change_executesequence_table
-{
- my ($mergemodulehash, $workdir, $idtfilename, $moduleidtfilename) = @_;
-
- my $infoline = "Changing content of table \"$idtfilename\"\n";
- $installer::logger::Lang->print($infoline);
-
- if ( ! -f $idtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$idtfilename\" in \"$workdir\" !", "change_executesequence_table"); }
- if ( ! -f $moduleidtfilename ) { installer::exiter::exit_program("ERROR: Could not find file \"$moduleidtfilename\" in \"$workdir\" !", "change_executesequence_table"); }
-
- # Reading file content
- my $idtfilecontent = installer::files::read_file($idtfilename);
- my $moduleidtfilecontent = installer::files::read_file($moduleidtfilename);
-
- # Converting to hash
- my $idtcontenthash = make_executeidtcontent_hash($idtfilecontent, $idtfilename);
- my $moduleidtcontenthash = make_moduleexecuteidtcontent_hash($moduleidtfilecontent, $moduleidtfilename);
-
- # Merging
- foreach my $action ( keys %{$moduleidtcontenthash} )
- {
- if ( exists($idtcontenthash->{$action}) ) { next; } # Action already exists, can be ignored
-
- if (( $idtfilename eq "InstallU.idt" ) && ( ! ( $action =~ /^\s*WindowsFolder\./ ))) { next; } # Only "WindowsFolder.*" CustomActions for UI Sequence table
-
- my $actionhashref = $moduleidtcontenthash->{$action};
- if ( $actionhashref->{'Sequence'} ne "" )
- {
- # Format for all sequence tables: Action Condition Sequence
- my $newline = $actionhashref->{'Action'} . "\t" . $actionhashref->{'Condition'} . "\t" . $actionhashref->{'Sequence'} . "\n";
- # Adding to table
- push(@{$idtfilecontent}, $newline);
- # Also adding to hash
- my %idttablehash = ();
- $idttablehash{'Action'} = $actionhashref->{'Action'};
- $idttablehash{'Condition'} = $actionhashref->{'Condition'};
- $idttablehash{'Sequence'} = $actionhashref->{'Sequence'};
- $idtcontenthash->{$action} = \%idttablehash;
-
- }
- else # no sequence defined, using syntax "BaseAction" and "After"
- {
- my $baseactionname = $actionhashref->{'BaseAction'};
- # If this baseactionname is not defined in execute idt file, it is not possible to merge
- if ( ! exists($idtcontenthash->{$baseactionname}) ) { installer::exiter::exit_program("ERROR: Merge problem: Could not find action \"$baseactionname\" in file \"$idtfilename\" !", "change_executesequence_table"); }
-
- my $baseaction = $idtcontenthash->{$baseactionname};
- my $sequencenumber = $baseaction->{'Sequence'};
- if ( $actionhashref->{'After'} == 1 ) { $sequencenumber = $sequencenumber + 1; }
- else { $sequencenumber = $sequencenumber - 1; }
-
- # Format for all sequence tables: Action Condition Sequence
- my $newline = $actionhashref->{'Action'} . "\t" . $actionhashref->{'Condition'} . "\t" . $sequencenumber . "\n";
- # Adding to table
- push(@{$idtfilecontent}, $newline);
- # Also adding to hash
- my %idttablehash = ();
- $idttablehash{'Action'} = $actionhashref->{'Action'};
- $idttablehash{'Condition'} = $actionhashref->{'Condition'};
- $idttablehash{'Sequence'} = $sequencenumber;
- $idtcontenthash->{$action} = \%idttablehash;
- }
- }
-
- # saving file
- installer::files::save_file($idtfilename, $idtfilecontent);
-}
-
-
-1;
diff --git a/solenv/bin/modules/installer/windows/msiglobal.pm b/solenv/bin/modules/installer/windows/msiglobal.pm
index 24342935643f..a02f20b3a982 100644
--- a/solenv/bin/modules/installer/windows/msiglobal.pm
+++ b/solenv/bin/modules/installer/windows/msiglobal.pm
@@ -166,193 +166,7 @@ sub generate_cab_file_list
if ( $^O =~ /cygwin/i ) { installer::worker::generate_cygwin_pathes($filesref); }
- if ( $installer::globals::use_packages_for_cabs )
- {
- my $sequenceorder = get_sequenceorder($filesref);
-
- my $counter = 1;
- my $currentcabfile = "";
-
- while ( ( exists($sequenceorder->{$counter}) ) || ( exists($installer::globals::allmergemodulefilesequences{$counter}) ) ) # Taking care of files from merge modules
- {
- if ( exists($installer::globals::allmergemodulefilesequences{$counter}) )
- {
- # Skipping this sequence, it is not included in $filesref, because it is assigned to a file from a merge module.\n";
- $counter++;
- next;
- }
-
- # Files with increasing sequencerorder are included in one cab file
- my $onefile = ${$filesref}[$sequenceorder->{$counter}];
- my $cabinetfile = $onefile->{'assignedcabinetfile'};
- my $sourcepath = $onefile->{'sourcepath'};
- if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
- my $uniquename = $onefile->{'uniquename'};
-
- my $styles = "";
- my $doinclude = 1;
- if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
- if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
-
- # to avoid lines with more than 256 characters, it can be useful to use relative pathes
- if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
-
- # all files with the same cabinetfile have increasing sequencenumbers
-
- my @ddffile = ();
-
- write_ddf_file_header(\@ddffile, $cabinetfile, $installdir);
-
- my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
- if ( $doinclude ) { push(@ddffile, $ddfline); }
-
- $counter++; # increasing the counter
- my $nextfile = "";
- my $nextcabinetfile = "";
- if ( exists($sequenceorder->{$counter}) ) { $nextfile = ${$filesref}[$sequenceorder->{$counter}]; }
- if ( $nextfile->{'assignedcabinetfile'} ) { $nextcabinetfile = $nextfile->{'assignedcabinetfile'}; }
-
- while ( $nextcabinetfile eq $cabinetfile )
- {
- $sourcepath = $nextfile->{'sourcepath'};
- if ( $^O =~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; }
- # to avoid lines with more than 256 characters, it can be useful to use relative pathes
- if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
- $uniquename = $nextfile->{'uniquename'};
- my $localdoinclude = 1;
- my $nextfilestyles = "";
- if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; }
- if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; }
- $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
- if ( $localdoinclude ) { push(@ddffile, $ddfline); }
-
- $counter++; # increasing the counter!
- $nextcabinetfile = "_lastfile_";
- if ( exists($sequenceorder->{$counter}) )
- {
- $nextfile = ${$filesref}[$sequenceorder->{$counter}];
- $nextcabinetfile = $nextfile->{'assignedcabinetfile'};
- }
- }
-
- # creating the DDF file
-
- my $ddffilename = $cabinetfile;
- $ddffilename =~ s/.cab/.ddf/;
- $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//;
- $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename;
-
- installer::files::save_file($ddffilename ,\@ddffile);
- my $infoline = "Created ddf file: $ddffilename\n";
- $installer::logger::Lang->print($infoline);
-
- # lines in ddf files must not be longer than 256 characters
- check_ddf_file(\@ddffile, $ddffilename);
-
- # Writing the makecab system call
-
- my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
-
- push(@cabfilelist, $oneline);
-
- # collecting all ddf files
- push(@installer::globals::allddffiles, $ddffilename);
- }
- }
- elsif ((( $installer::globals::cab_file_per_component ) || ( $installer::globals::fix_number_of_cab_files )) && ( $installer::globals::updatedatabase ))
- {
- my $sequenceorder = get_sequenceorder($filesref);
-
- my $counter = 1;
- my $currentcabfile = "";
-
- while ( ( exists($sequenceorder->{$counter}) ) || ( exists($installer::globals::allmergemodulefilesequences{$counter}) ) ) # Taking care of files from merge modules
- {
-# if ( exists($installer::globals::allmergemodulefilesequences{$counter}) )
-# {
-# # Skipping this sequence, it is not included in $filesref, because it is assigned to a file from a merge module.\n";
-# $counter++;
-# next;
-# }
-
- my $onefile = ${$filesref}[$sequenceorder->{$counter}];
- $counter++;
-
- my $cabinetfile = $onefile->{'cabinet'};
- my $sourcepath = $onefile->{'sourcepath'};
- if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
- my $uniquename = $onefile->{'uniquename'};
-
- my $styles = "";
- my $doinclude = 1;
- if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
- if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
-
- # to avoid lines with more than 256 characters, it can be useful to use relative pathes
- if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
-
- my @ddffile = ();
-
- write_ddf_file_header(\@ddffile, $cabinetfile, $installdir);
-
- my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
- if ( $doinclude ) { push(@ddffile, $ddfline); }
-
- my $nextfile = "";
- if ( ${$filesref}[$sequenceorder->{$counter}] ) { $nextfile = ${$filesref}[$sequenceorder->{$counter}]; }
-
- my $nextcabinetfile = "";
-
- if ( $nextfile->{'cabinet'} ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
-
- while ( $nextcabinetfile eq $cabinetfile )
- {
- $sourcepath = $nextfile->{'sourcepath'};
- if ( $^O =~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; }
- # to avoid lines with more than 256 characters, it can be useful to use relative pathes
- if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
- $uniquename = $nextfile->{'uniquename'};
- my $localdoinclude = 1;
- my $nextfilestyles = "";
- if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; }
- if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; }
- $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
- if ( $localdoinclude ) { push(@ddffile, $ddfline); }
- $counter++; # increasing the counter!
- $nextfile = "";
- $nextcabinetfile = "_lastfile_";
- if (( exists($sequenceorder->{$counter}) ) && ( ${$filesref}[$sequenceorder->{$counter}] ))
- {
- $nextfile = ${$filesref}[$sequenceorder->{$counter}];
- $nextcabinetfile = $nextfile->{'cabinet'};
- }
- }
-
- # creating the DDF file
-
- my $ddffilename = $cabinetfile;
- $ddffilename =~ s/.cab/.ddf/;
- $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//;
- $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename;
-
- installer::files::save_file($ddffilename ,\@ddffile);
- my $infoline = "Created ddf file: $ddffilename\n";
- $installer::logger::Lang->print($infoline);
-
- # lines in ddf files must not be longer than 256 characters
- check_ddf_file(\@ddffile, $ddffilename);
-
- # Writing the makecab system call
-
- my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
-
- push(@cabfilelist, $oneline);
-
- # collecting all ddf files
- push(@installer::globals::allddffiles, $ddffilename);
- }
- }
- elsif (( $installer::globals::cab_file_per_component ) || ( $installer::globals::fix_number_of_cab_files ))
+ if ( $installer::globals::fix_number_of_cab_files )
{
for ( my $i = 0; $i <= $#{$filesref}; $i++ )
{
@@ -428,69 +242,6 @@ sub generate_cab_file_list
push(@installer::globals::allddffiles, $ddffilename);
}
}
- elsif (( $installer::globals::one_cab_file ) && ( $installer::globals::updatedatabase ))
- {
- my $sequenceorder = get_sequenceorder($filesref);
-
- my $counter = 1;
- my $currentcabfile = "";
-
- while ( ( exists($sequenceorder->{$counter}) ) || ( exists($installer::globals::allmergemodulefilesequences{$counter}) ) ) # Taking care of files from merge modules
- {
- if ( exists($installer::globals::allmergemodulefilesequences{$counter}) )
- {
- # Skipping this sequence, it is not included in $filesref, because it is assigned to a file from a merge module.\n";
- $counter++;
- next;
- }
-
- my $onefile = ${$filesref}[$sequenceorder->{$counter}];
-
- $cabinetfile = $onefile->{'cabinet'};
- my $sourcepath = $onefile->{'sourcepath'};
- if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
- my $uniquename = $onefile->{'uniquename'};
-
- # to avoid lines with more than 256 characters, it can be useful to use relative pathes
- if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
-
- if ( $counter == 1 ) { write_ddf_file_header(\@ddffile, $cabinetfile, $installdir); }
-
- my $styles = "";
- my $doinclude = 1;
- if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
- if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
-
- my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
- if ( $doinclude ) { push(@ddffile, $ddfline); }
-
- $counter++; # increasing the counter
- }
-
- # creating the DDF file
-
- my $ddffilename = $cabinetfile;
- $ddffilename =~ s/.cab/.ddf/;
- $ddfdir =~ s/[\/\\]\s*$//;
- $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename;
-
- installer::files::save_file($ddffilename ,\@ddffile);
- my $infoline = "Created ddf file: $ddffilename\n";
- $installer::logger::Lang->print($infoline);
-
- # lines in ddf files must not be longer than 256 characters
- check_ddf_file(\@ddffile, $ddffilename);
-
- # Writing the makecab system call
-
- # my $oneline = "makecab.exe /F " . $ddffilename . "\n";
- my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
-
- push(@cabfilelist, $oneline);
-
- # collecting all ddf files
- push(@installer::globals::allddffiles, $ddffilename);
- }
elsif ( $installer::globals::one_cab_file )
{
my @ddffile = ();
@@ -1405,28 +1156,6 @@ sub copy_windows_installer_files_into_installset
}
#################################################################
-# Copying MergeModules for the Windows installer into the
-# installation set. The list of MergeModules is located
-# in %installer::globals::copy_msm_files
-#################################################################
-
-sub copy_merge_modules_into_installset
-{
- my ($installdir) = @_;
-
- installer::logger::include_header_into_logfile("Copying Merge files into installation set");
-
- my $cabfile;
- foreach $cabfile ( keys %installer::globals::copy_msm_files )
- {
- my $sourcefile = $installer::globals::copy_msm_files{$cabfile};
- my $destfile = $installdir . $installer::globals::separator . $cabfile;
-
- installer::systemactions::copy_one_file($sourcefile, $destfile);
- }
-}
-
-#################################################################
# Copying the child projects into the
# installation set
#################################################################
@@ -2016,11 +1745,7 @@ sub set_global_code_variables
}
# ProductCode must not change, if Windows patches shall be applied
- if ( $installer::globals::updatedatabase )
- {
- $installer::globals::productcode = $alloldproperties->{'ProductCode'};
- }
- elsif ( $installer::globals::prepare_winpatch )
+ if ( $installer::globals::prepare_winpatch )
{
# ProductCode has to be specified in each language
my $searchstring = "PRODUCTCODE";
diff --git a/solenv/bin/modules/installer/windows/msp.pm b/solenv/bin/modules/installer/windows/msp.pm
deleted file mode 100644
index 735377439fc5..000000000000
--- a/solenv/bin/modules/installer/windows/msp.pm
+++ /dev/null
@@ -1,1493 +0,0 @@
-#**************************************************************
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#**************************************************************
-
-
-
-package installer::windows::msp;
-
-use File::Copy;
-use installer::control;
-use installer::converter;
-use installer::exiter;
-use installer::files;
-use installer::globals;
-use installer::logger;
-use installer::pathanalyzer;
-use installer::systemactions;
-use installer::windows::admin;
-use installer::windows::idtglobal;
-use installer::windows::update;
-
-#################################################################################
-# Making all required administrative installations
-#################################################################################
-
-sub install_installation_sets
-{
- my ($installationdir) = @_;
-
- # Finding the msi database in the new installation set, that is located in $installationdir
-
- my $msifiles = installer::systemactions::find_file_with_file_extension("msi", $installationdir);
-
- if ( $#{$msifiles} < 0 ) { installer::exiter::exit_program("ERROR: Did not find msi database in directory $installationdir", "create_msp_patch"); }
- if ( $#{$msifiles} > 0 ) { installer::exiter::exit_program("ERROR: Did find more than one msi database in directory $installationdir", "create_msp_patch"); }
-
- my $newinstallsetdatabasepath = $installationdir . $installer::globals::separator . ${$msifiles}[0];
- my $oldinstallsetdatabasepath = $installer::globals::updatedatabasepath;
-
- # Creating temp directory again
- installer::systemactions::create_directory_structure($installer::globals::temppath);
-
- # Creating old installation directory
- my $dirname = "admin";
- my $installpath = $installer::globals::temppath . $installer::globals::separator . $dirname;
- if ( ! -d $installpath) { installer::systemactions::create_directory($installpath); }
-
- my $oldinstallpath = $installpath . $installer::globals::separator . "old";
- my $newinstallpath = $installpath . $installer::globals::separator . "new";
-
- if ( ! -d $oldinstallpath) { installer::systemactions::create_directory($oldinstallpath); }
- if ( ! -d $newinstallpath) { installer::systemactions::create_directory($newinstallpath); }
-
- my $olddatabase = installer::windows::admin::make_admin_install($oldinstallsetdatabasepath, $oldinstallpath);
- my $newdatabase = installer::windows::admin::make_admin_install($newinstallsetdatabasepath, $newinstallpath);
-
- if ( $^O =~ /cygwin/i ) {
- $olddatabase = qx{cygpath -w "$olddatabase"};
- $olddatabase =~ s/\s*$//g;
- $newdatabase = qx{cygpath -w "$newdatabase"};
- $newdatabase =~ s/\s*$//g;
- }
-
- return ($olddatabase, $newdatabase);
-}
-
-#################################################################################
-# Collecting the destinations of all files with flag PATCH in a hash.
-#################################################################################
-
-sub collect_patch_file_destinations
-{
- my ( $filesarray ) = @_;
-
- my %patchfiledestinations = ();
- my %nopatchfiledestinations = ();
- my $patchcounter = 0;
- my $nopatchcounter = 0;
-
- for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
- {
- my $onefile = ${$filesarray}[$i];
- my $styles = "";
-
- if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'} };
-
- if ( $styles =~ /\bPATCH\b/ )
- {
- $patchfiledestinations{$onefile->{'destination'}} = 1;
- $patchcounter++;
- }
- else
- {
- $nopatchfiledestinations{$onefile->{'destination'}} = 1;
- $nopatchcounter++;
- }
- }
-
- return (\%patchfiledestinations, \%nopatchfiledestinations, $patchcounter, $nopatchcounter);
-}
-
-#################################################################################
-# Returning the first path segment of a path
-#################################################################################
-
-sub get_first_path_segment
-{
- my ( $path ) = @_;
-
- my $firstsegment = "";
- my $remainder = $path;
-
- if ( $path =~ /^\s*(.*?)[\/\\](.*)\s*$/ )
- {
- $firstsegment = $1;
- $remainder = $2;
- }
-
- return ($firstsegment, $remainder);
-}
-
-#################################################################################
-# Finding the flexible path in the destinations, that are saved in
-# the hash $nopatchfiledestinations.
-#################################################################################
-
-sub prepare_path_in_nopatchfilehash
-{
- my ($nopatchfiledestinations, $newpath) = @_;
-
- my $infoline = "";
- my $flexiblepath = "";
- my $found = 0;
- my %checked_destinations = ();
-
- foreach my $onedestination ( keys %{$nopatchfiledestinations} )
- {
- $flexiblepath = "";
- $found = 0;
-
- my $found_first_segement = 1;
- my $firstsegement = "";
- my $fixedpath = $onedestination;
- my $testfile = $newpath . $installer::globals::separator . $fixedpath;
-
- while (( ! -f $testfile ) && ( $found_first_segement ))
- {
- $firstsegement = "";
- ( $firstsegement, $fixedpath ) = get_first_path_segment($fixedpath);
-
- if ( $firstsegement ne "" )
- {
- $found_first_segement = 1;
- $flexiblepath = $flexiblepath . $firstsegement . $installer::globals::separator;
- }
- else
- {
- $found_first_segement = 0;
- }
-
- $testfile = $newpath . $installer::globals::separator . $fixedpath;
- }
-
- if ( -f $testfile ) { $found = 1; }
-
- if ( $found ) { last; }
- }
-
- if ( ! $found ) { installer::exiter::exit_program("ERROR: Could not determine flexible destination path for msp patch creation!", "prepare_path_in_nopatchfilehash"); }
-
- $infoline = "Setting flexible path for msp creation: $flexiblepath\n";
- $installer::logger::Lang->print($infoline);
-
- foreach my $onedestination ( keys %{$nopatchfiledestinations} )
- {
- $onedestination =~ s/^\s*\Q$flexiblepath\E//;
- $checked_destinations{$onedestination} = 1;
- }
-
- return \%checked_destinations;
-}
-
-#################################################################################
-# Synchronizing the two installed products in that way, that only
-# files with flag PATCH are different.
-#################################################################################
-
-sub synchronize_installation_sets
-{
- my ($olddatabase, $newdatabase, $filesarray) = @_;
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->print("Synchronizing installed products because of PATCH flag\n");
- $infoline = "Old product: $olddatabase\n";
- $installer::logger::Lang->print($infoline);
- $infoline = "New product: $newdatabase\n";
- $installer::logger::Lang->print($infoline);
-
- my ( $patchfiledestinations, $nopatchfiledestinations, $patchfilecounter, $nopatchfilecounter ) = collect_patch_file_destinations($filesarray);
-
- $infoline = "Number of files with PATCH flag: $patchfilecounter\n";
- $installer::logger::Lang->print($infoline);
-
- $infoline = "Number of files without PATCH flag: $nopatchfilecounter\n";
- $installer::logger::Lang->print($infoline);
-
- foreach my $localfile ( sort keys %{$patchfiledestinations} )
- {
- $infoline = "\tPATCH file: $localfile\n";
- $installer::logger::Lang->print($infoline);
- }
-
- my $oldpath = $olddatabase;
- if ( $^O =~ /cygwin/i ) { $oldpath =~ s/\\/\//g; }
- installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldpath);
- $oldpath =~ s/\\\s*$//;
- $oldpath =~ s/\/\s*$//;
-
- my $newpath = $newdatabase;
- if ( $^O =~ /cygwin/i ) { $newpath =~ s/\\/\//g; }
- installer::pathanalyzer::get_path_from_fullqualifiedname(\$newpath);
- $newpath =~ s/\\\s*$//;
- $newpath =~ s/\/\s*$//;
-
- # The destination path is not correct. destinations in the hash contain
- # the flexible installation path, that is not part in the administrative installation
- $nopatchfiledestinations = prepare_path_in_nopatchfilehash($nopatchfiledestinations, $newpath);
-
- foreach my $onedestination ( keys %{$nopatchfiledestinations} )
- {
- my $source = $oldpath . $installer::globals::separator . $onedestination;
- my $dest = $newpath . $installer::globals::separator . $onedestination;
-
- if ( -f $source )
- {
- if ( -f $dest )
- {
- my $copyreturn = copy($source, $dest);
- # installer::systemactions::copy_one_file($source, $dest);
- # $infoline = "Synchronizing file: $source to $dest\n";
- # $installer::logger::Lang->print($infoline);
- }
- else
- {
- $infoline = "Not synchronizing. Destination file \"$dest\" does not exist.\n";
- $installer::logger::Lang->print($infoline);
- }
- }
- else
- {
- $infoline = "Not synchronizing. Source file \"$source\" does not exist.\n";
- $installer::logger::Lang->print($infoline);
- }
- }
-}
-
-#################################################################################
-# Extracting all tables from a pcp file
-#################################################################################
-
-sub extract_all_tables_from_pcpfile
-{
- my ($fullpcpfilepath, $workdir) = @_;
-
- my $msidb = "msidb.exe"; # Has to be in the path
- my $infoline = "";
- my $systemcall = "";
- my $returnvalue = "";
- my $extraslash = ""; # Has to be set for non-ActiveState perl
-
- my $localfullpcpfile = $fullpcpfilepath;
- my $localworkdir = $workdir;
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- $localfullpcpfile =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- $extraslash = "\\";
- }
-
- # Export of all tables by using "*"
-
- $systemcall = $msidb . " -d " . $localfullpcpfile . " -f " . $localworkdir . " -e " . $extraslash . "*";
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not exclude tables from pcp file: $fullpcpfilepath !", "extract_all_tables_from_msidatabase");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-}
-
-#################################################################################
-# Include tables into a pcp file
-#################################################################################
-
-sub include_tables_into_pcpfile
-{
- my ($fullpcpfilepath, $workdir, $tables) = @_;
-
- my $msidb = "msidb.exe"; # Has to be in the path
- my $infoline = "";
- my $systemcall = "";
- my $returnvalue = "";
-
- # Make all table 8+3 conform
- my $alltables = installer::converter::convert_stringlist_into_array(\$tables, " ");
-
- for ( my $i = 0; $i <= $#{$alltables}; $i++ )
- {
- my $tablename = ${$alltables}[$i];
- $tablename =~ s/\s*$//;
- my $namelength = length($tablename);
- if ( $namelength > 8 )
- {
- my $newtablename = substr($tablename, 0, 8); # name, offset, length
- my $oldfile = $workdir . $installer::globals::separator . $tablename . ".idt";
- my $newfile = $workdir . $installer::globals::separator . $newtablename . ".idt";
- if ( -f $newfile ) { unlink $newfile; }
- installer::systemactions::copy_one_file($oldfile, $newfile);
- }
- }
-
- # Import of tables
-
- my $localworkdir = $workdir;
- my $localfullpcpfilepath = $fullpcpfilepath;
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- $localfullpcpfilepath =~ s/\//\\\\/g;
- $localworkdir =~ s/\//\\\\/g;
- }
-
- $systemcall = $msidb . " -d " . $localfullpcpfilepath . " -f " . $localworkdir . " -i " . $tables;
-
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not include tables into pcp file: $fullpcpfilepath !", "include_tables_into_pcpfile");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-}
-
-#################################################################################
-# Calling msimsp.exe
-#################################################################################
-
-sub execute_msimsp
-{
- my ($fullpcpfilename, $mspfilename, $localmspdir) = @_;
-
- my $msimsp = "msimsp.exe"; # Has to be in the path
- my $infoline = "";
- my $systemcall = "";
- my $returnvalue = "";
- my $logfilename = $localmspdir . $installer::globals::separator . "msimsp.log";
-
- # Using a specific temp for each msimsp.exe process
- # Creating temp directory again (should already have happened)
- installer::systemactions::create_directory_structure($installer::globals::temppath);
-
- # Creating old installation directory
- my $dirname = "msimsptemp";
- my $msimsptemppath = $installer::globals::temppath . $installer::globals::separator . $dirname;
- if ( ! -d $msimsptemppath) { installer::systemactions::create_directory($msimsptemppath); }
-
- # 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
-
- if ( -f $logfilename ) { unlink $logfilename; }
-
- my $localfullpcpfilename = $fullpcpfilename;
- my $localmspfilename = $mspfilename;
- my $locallogfilename = $logfilename;
- my $localmsimsptemppath = $msimsptemppath;
-
- if ( $^O =~ /cygwin/i ) {
- # msimsp.exe really wants backslashes. (And double escaping because system() expands the string.)
- $localfullpcpfilename =~ s/\//\\\\/g;
- $locallogfilename =~ s/\//\\\\/g;
-
- $localmspfilename =~ s/\\/\\\\/g; # path already contains backslash
- # $localmspfilename =~ s/\//\\\\/g;
-
- $localmsimsptemppath = qx{cygpath -w "$localmsimsptemppath"};
- $localmsimsptemppath =~ s/\\/\\\\/g;
- $localmsimsptemppath =~ s/\s*$//g;
- }
-
- $systemcall = $msimsp . " -s " . $localfullpcpfilename . " -p " . $localmspfilename . " -l " . $locallogfilename . " -f " . $localmsimsptemppath;
- $installer::logger::Info->printf("... %s ...\n", $systemcall);
-
- $returnvalue = system($systemcall);
-
- $infoline = "Systemcall: $systemcall\n";
- $installer::logger::Lang->print($infoline);
-
- if ($returnvalue)
- {
- $infoline = "ERROR: Could not execute $systemcall !\n";
- $installer::logger::Lang->print($infoline);
- installer::exiter::exit_program("ERROR: Could not execute $systemcall !", "execute_msimsp");
- }
- else
- {
- $infoline = "Success: Executed $systemcall successfully!\n";
- $installer::logger::Lang->print($infoline);
- }
-
- return $logfilename;
-}
-
-####################################################################
-# Checking existence and saving all tables, that need to be edited
-####################################################################
-
-sub check_and_save_tables
-{
- my ($tablelist, $workdir) = @_;
-
- my $tables = installer::converter::convert_stringlist_into_array(\$tablelist, " ");
-
- for ( my $i = 0; $i <= $#{$tables}; $i++ )
- {
- my $filename = ${$tables}[$i];
- $filename =~ s/\s*$//;
- my $fullfilename = $workdir . $installer::globals::separator . $filename . ".idt";
-
- if ( ! -f $fullfilename ) { installer::exiter::exit_program("ERROR: Required idt file could not be found: \"$fullfilename\"!", "check_and_save_tables"); }
-
- my $savfilename = $fullfilename . ".sav";
- installer::systemactions::copy_one_file($fullfilename, $savfilename);
- }
-}
-
-####################################################################
-# Setting the languages for the service packs
-####################################################################
-
-sub create_langstring
-{
- my ( $languagesarrayref ) = @_;
-
- my $langstring = "";
- for ( my $i = 0; $i <= $#{$languagesarrayref}; $i++ ) { $langstring = $langstring . "_" . ${$languagesarrayref}[$i]; }
-
- return $langstring;
-}
-
-####################################################################
-# Setting the name of the msp database
-####################################################################
-
-sub set_mspfilename
-{
- my ($allvariables, $mspdir, $languagesarrayref) = @_;
-
- my $databasename = $allvariables->{'PRODUCTNAME'};
- $databasename = lc($databasename);
- $databasename =~ s/\.//g;
- $databasename =~ s/\-//g;
- $databasename =~ s/\s//g;
-
- if ( $allvariables->{'MSPPRODUCTVERSION'} ) { $databasename = $databasename . $allvariables->{'MSPPRODUCTVERSION'}; }
-
- # possibility to overwrite the name with variable DATABASENAME
- # if ( $allvariables->{'DATABASENAME'} ) { $databasename = $allvariables->{'DATABASENAME'}; }
-
- # Adding patch info to database name
- # if ( $installer::globals::buildid ) { $databasename = $databasename . "_" . $installer::globals::buildid; }
-
- # if ( $allvariables->{'VENDORPATCHVERSION'} ) { $databasename = $databasename . "_" . $allvariables->{'VENDORPATCHVERSION'}; }
-
-
- if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 ))
- {
- my $windowspatchlevel = 0;
- if ( $allvariables->{'MSPPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'MSPPATCHLEVEL'}; }
- $databasename = $databasename . "_servicepack_" . $windowspatchlevel;
- my $languagestring = create_langstring($languagesarrayref);
- $databasename = $databasename . $languagestring;
- }
- else
- {
- my $hotfixaddon = "hotfix_";
- $hotfixaddon = $hotfixaddon . $installer::globals::buildid;
- my $cwsname = "";
- if ( $ENV{'CWS_WORK_STAMP'} ) { $hotfixaddon = $ENV{'CWS_WORK_STAMP'}; }
- if ( $allvariables->{'OVERWRITE_CWSNAME'} ) { $hotfixaddon = $allvariables->{'OVERWRITE_CWSNAME'}; }
- $databasename = $databasename . "_" . $hotfixaddon;
- }
-
- $databasename = $databasename . ".msp";
-
- my $fullmspname = $mspdir . $installer::globals::separator . $databasename;
-
- if ( $^O =~ /cygwin/i ) { $fullmspname =~ s/\//\\/g; }
-
- return $fullmspname;
-}
-
-####################################################################
-# Editing table Properties
-####################################################################
-
-sub change_properties_table
-{
- my ($localmspdir, $mspfilename) = @_;
-
- my $infoline = "Changing content of table \"Properties\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "Properties.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_properties_table"); }
-
- my $filecontent = installer::files::read_file($filename);
-
-
- my $guidref = installer::windows::msiglobal::get_guid_list(1, 1);
- ${$guidref}[0] =~ s/\s*$//; # removing ending spaces
- my $patchcode = "\{" . ${$guidref}[0] . "\}";
-
- # Setting "PatchOutputPath"
- my $found_patchoutputpath = 0;
- my $found_patchguid = 0;
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( ${$filecontent}[$i] =~ /^\s*PatchOutputPath\t(.*?)\s*$/ )
- {
- my $oldvalue = $1;
- ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$mspfilename/;
- $found_patchoutputpath = 1;
- }
-
- if ( ${$filecontent}[$i] =~ /^\s*PatchGUID\t(.*?)\s*$/ )
- {
- my $oldvalue = $1;
- ${$filecontent}[$i] =~ s/\Q$oldvalue\E/$patchcode/;
- $found_patchguid = 1;
- }
- }
-
- if ( ! $found_patchoutputpath )
- {
- my $newline = "PatchOutputPath\t$mspfilename\n";
- push(@{$filecontent}, $newline);
- }
-
- if ( ! $found_patchguid )
- {
- my $newline = "PatchGUID\t$patchcode\n";
- push(@{$filecontent}, $newline);
- }
-
- # saving file
- installer::files::save_file($filename, $filecontent);
-}
-
-####################################################################
-# Editing table TargetImages
-####################################################################
-
-sub change_targetimages_table
-{
- my ($localmspdir, $olddatabase) = @_;
-
- my $infoline = "Changing content of table \"TargetImages\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "TargetImages.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_targetimages_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my @newcontent = ();
-
- # Copying the header
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
-
- #Adding all targets
- my $newline = "T1\t$olddatabase\t\tU1\t1\t0x00000922\t1\n";
- push(@newcontent, $newline);
-
- # saving file
- installer::files::save_file($filename, \@newcontent);
-}
-
-####################################################################
-# Editing table UpgradedImages
-####################################################################
-
-sub change_upgradedimages_table
-{
- my ($localmspdir, $newdatabase) = @_;
-
- my $infoline = "Changing content of table \"UpgradedImages\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "UpgradedImages.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_upgradedimages_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my @newcontent = ();
-
- # Copying the header
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
-
- # Syntax: Upgraded MsiPath PatchMsiPath SymbolPaths Family
-
- # default values
- my $upgraded = "U1";
- my $msipath = $newdatabase;
- my $patchmsipath = "";
- my $symbolpaths = "";
- my $family = "22334455";
-
- if ( $#{$filecontent} >= 3 )
- {
- my $line = ${$filecontent}[3];
- if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
- {
- $upgraded = $1;
- $patchmsipath = $3;
- $symbolpaths = $4;
- $family = $5;
- }
- }
-
- #Adding sequence line, saving PatchFamily
- my $newline = "$upgraded\t$msipath\t$patchmsipath\t$symbolpaths\t$family\n";
- push(@newcontent, $newline);
-
- # saving file
- installer::files::save_file($filename, \@newcontent);
-}
-
-####################################################################
-# Editing table ImageFamilies
-####################################################################
-
-sub change_imagefamilies_table
-{
- my ($localmspdir) = @_;
-
- my $infoline = "Changing content of table \"ImageFamilies\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "ImageFamilies.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_imagefamilies_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my @newcontent = ();
-
- # Copying the header
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
-
- # Syntax: Family MediaSrcPropName MediaDiskId FileSequenceStart DiskPrompt VolumeLabel
- # "FileSequenceStart has to be set
-
- # Default values:
-
- my $family = "22334455";
- my $mediasrcpropname = "MediaSrcPropName";
- my $mediadiskid = "2";
- my $filesequencestart = get_filesequencestart();
- my $diskprompt = "";
- my $volumelabel = "";
-
- if ( $#{$filecontent} >= 3 )
- {
- my $line = ${$filecontent}[3];
- if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
- {
- $family = $1;
- $mediasrcpropname = $2;
- $mediadiskid = $3;
- $diskprompt = $5;
- $volumelabel = $6;
- }
- }
-
- #Adding sequence line
- my $newline = "$family\t$mediasrcpropname\t$mediadiskid\t$filesequencestart\t$diskprompt\t$volumelabel\n";
- push(@newcontent, $newline);
-
- # saving file
- installer::files::save_file($filename, \@newcontent);
-}
-
-####################################################################
-# Setting start sequence for patch
-####################################################################
-
-sub get_filesequencestart
-{
- my $sequence = 1000; # default
-
- if ( $installer::globals::updatelastsequence ) { $sequence = $installer::globals::updatelastsequence + 500; }
-
- return $sequence;
-}
-
-####################################################################
-# Setting time value into pcp file
-# Format mm/dd/yyyy hh:mm
-####################################################################
-
-sub get_patchtime_value
-{
- # Syntax: 8/8/2008 11:55
- my $minute = (localtime())[1];
- my $hour = (localtime())[2];
- my $day = (localtime())[3];
- my $month = (localtime())[4];
- my $year = 1900 + (localtime())[5];
-
- $month++; # zero based month
- if ( $minute < 10 ) { $minute = "0" . $minute; }
- if ( $hour < 10 ) { $hour = "0" . $hour; }
-
- my $timestring = $month . "/" . $day . "/" . $year . " " . $hour . ":" . $minute;
-
- return $timestring;
-}
-
-#################################################################################
-# Checking, if this is the correct database.
-#################################################################################
-
-sub correct_langs
-{
- my ($langs, $languagestringref) = @_;
-
- my $correct_langs = 0;
-
- # Comparing $langs with $languagestringref
-
- my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ",");
- my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_");
-
- my $not_included = 0;
- foreach my $onelang ( keys %{$langlisthash} )
- {
- if ( ! exists($langstringhash->{$onelang}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included )
- {
- foreach my $onelanguage ( keys %{$langstringhash} )
- {
- if ( ! exists($langlisthash->{$onelanguage}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included ) { $correct_langs = 1; }
- }
-
- return $correct_langs;
-}
-
-#################################################################################
-# Searching for the path to the reference database for this special product.
-#################################################################################
-
-sub get_patchid_from_list
-{
- my ($filecontent, $languagestringref, $filename) = @_;
-
- my $patchid = "";
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- my $line = ${$filecontent}[$i];
- if ( $line =~ /^\s*$/ ) { next; } # empty line
- if ( $line =~ /^\s*\#/ ) { next; } # comment line
-
- if ( $line =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/ )
- {
- my $langs = $1;
- my $localpatchid = $2;
-
- if ( correct_langs($langs, $languagestringref) )
- {
- $patchid = $localpatchid;
- last;
- }
- }
- else
- {
- installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_patchid_from_list");
- }
- }
-
- return $patchid;
-}
-
-####################################################################
-# Editing table PatchMetadata
-####################################################################
-
-sub change_patchmetadata_table
-{
- my ($localmspdir, $allvariables, $languagestringref) = @_;
-
- my $infoline = "Changing content of table \"PatchMetadata\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "PatchMetadata.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchmetadata_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my @newcontent = ();
-
- # Syntax: Company Property Value
- # Interesting properties: "Classification" and "CreationTimeUTC"
-
- my $classification_set = 0;
- my $creationtime_set = 0;
- my $targetproductname_set = 0;
- my $manufacturer_set = 0;
- my $displayname_set = 0;
- my $description_set = 0;
- my $allowremoval_set = 0;
-
- my $defaultcompany = "";
-
- my $classificationstring = "Classification";
- my $classificationvalue = "Hotfix";
- if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $classificationvalue = "ServicePack"; }
-
- my $allowremovalstring = "AllowRemoval";
- my $allowremovalvalue = "1";
- if (( exists($allvariables->{'MSPALLOWREMOVAL'}) ) && ( $allvariables->{'MSPALLOWREMOVAL'} == 0 )) { $allowremovalvalue = 0; }
-
- my $timestring = "CreationTimeUTC";
- # Syntax: 8/8/2008 11:55
- my $timevalue = get_patchtime_value();
-
- my $targetproductnamestring = "TargetProductName";
- my $targetproductnamevalue = $allvariables->{'PRODUCTNAME'};
- if ( $allvariables->{'PROPERTYTABLEPRODUCTNAME'} ) { $targetproductnamevalue = $allvariables->{'PROPERTYTABLEPRODUCTNAME'}; }
-
- my $manufacturerstring = "ManufacturerName";
- my $manufacturervalue = "Apache OpenOffice";
- if ( $installer::globals::longmanufacturer ) { $manufacturervalue = $installer::globals::longmanufacturer; }
-
- my $displaynamestring = "DisplayName";
- my $descriptionstring = "Description";
- my $displaynamevalue = "";
- my $descriptionvalue = "";
-
- my $base = $allvariables->{'PRODUCTNAME'} . " " . $allvariables->{'PRODUCTVERSION'};
- if ( $installer::globals::languagepack ) { $base = $targetproductnamevalue; }
-
- my $windowspatchlevel = 0;
- if ( $allvariables->{'WINDOWSPATCHLEVEL'} ) { $windowspatchlevel = $allvariables->{'WINDOWSPATCHLEVEL'}; }
-
- my $displayaddon = "";
- if ( $allvariables->{'PATCHDISPLAYADDON'} ) { $displayaddon = $allvariables->{'PATCHDISPLAYADDON'}; }
-
- my $cwsname = "";
- if ( $ENV{'CWS_WORK_STAMP'} ) { $cwsname = $ENV{'CWS_WORK_STAMP'}; }
- if (( $cwsname ne "" ) && ( $allvariables->{'OVERWRITE_CWSNAME'} )) { $cwsname = $allvariables->{'OVERWRITE_CWSNAME'}; }
-
- my $patchsequence = get_patchsequence($allvariables);
-
- if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 ))
- {
- $displaynamevalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid;
- $descriptionvalue = $base . " ServicePack " . $windowspatchlevel . " " . $patchsequence . " Build: " . $installer::globals::buildid;
- }
- else
- {
- $displaynamevalue = $base . " Hotfix " . $cwsname . " " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid;
- $descriptionvalue = $base . " Hotfix " . $cwsname . " " . $displayaddon . " " . $patchsequence . " Build: " . $installer::globals::buildid;
- $displaynamevalue =~ s/ / /g;
- $descriptionvalue =~ s/ / /g;
- $displaynamevalue =~ s/ / /g;
- $descriptionvalue =~ s/ / /g;
- $displaynamevalue =~ s/ / /g;
- $descriptionvalue =~ s/ / /g;
- }
-
- if ( $allvariables->{'MSPPATCHNAMELIST'} )
- {
- my $patchnamelistfile = $allvariables->{'MSPPATCHNAMELIST'};
- $patchnamelistfile = $installer::globals::idttemplatepath . $installer::globals::separator . $patchnamelistfile;
- if ( ! -f $patchnamelistfile ) { installer::exiter::exit_program("ERROR: Could not find file \"$patchnamelistfile\".", "change_patchmetadata_table"); }
- my $filecontent = installer::files::read_file($patchnamelistfile);
-
- # Get name and path of reference database
- my $patchid = get_patchid_from_list($filecontent, $languagestringref, $patchnamelistfile);
-
- if ( $patchid eq "" ) { installer::exiter::exit_program("ERROR: Could not find file patchid in file \"$patchnamelistfile\" for language(s) \"$$languagestringref\".", "change_patchmetadata_table"); }
-
- # Setting language specific patch id
- }
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if ( ${$filecontent}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\s*$/ )
- {
- my $company = $1;
- my $property = $2;
- my $value = $3;
-
- if ( $property eq $classificationstring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$classificationvalue\n";
- $classification_set = 1;
- }
-
- if ( $property eq $allowremovalstring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$allowremovalvalue\n";
- $allowremoval_set = 1;
- }
-
- if ( $property eq $timestring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$timevalue\n";
- $creationtime_set = 1;
- }
-
- if ( $property eq $targetproductnamestring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$targetproductnamevalue\n";
- $targetproductname_set = 1;
- }
-
- if ( $property eq $manufacturerstring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$manufacturervalue\n";
- $manufacturer_set = 1;
- }
-
- if ( $property eq $displaynamestring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$displaynamevalue\n";
- $displayname_set = 1;
- }
-
- if ( $property eq $descriptionstring )
- {
- ${$filecontent}[$i] = "$company\t$property\t$descriptionvalue\n";
- $description_set = 1;
- }
- }
-
- push(@newcontent, ${$filecontent}[$i]);
- }
-
- if ( ! $classification_set )
- {
- my $line = "$defaultcompany\t$classificationstring\t$classificationvalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $allowremoval_set )
- {
- my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $allowremoval_set )
- {
- my $line = "$defaultcompany\t$classificationstring\t$allowremovalvalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $creationtime_set )
- {
- my $line = "$defaultcompany\t$timestring\t$timevalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $targetproductname_set )
- {
- my $line = "$defaultcompany\t$targetproductnamestring\t$targetproductnamevalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $manufacturer_set )
- {
- my $line = "$defaultcompany\t$manufacturerstring\t$manufacturervalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $displayname_set )
- {
- my $line = "$defaultcompany\t$displaynamestring\t$displaynamevalue\n";
- push(@newcontent, $line);
- }
-
- if ( ! $description_set )
- {
- my $line = "$defaultcompany\t$descriptionstring\t$descriptionvalue\n";
- push(@newcontent, $line);
- }
-
- # saving file
- installer::files::save_file($filename, \@newcontent);
-}
-
-####################################################################
-# Editing table PatchSequence
-####################################################################
-
-sub change_patchsequence_table
-{
- my ($localmspdir, $allvariables) = @_;
-
- my $infoline = "Changing content of table \"PatchSequence\"\n";
- $installer::logger::Lang->print($infoline);
-
- my $filename = $localmspdir . $installer::globals::separator . "PatchSequence.idt";
- if ( ! -f $filename ) { installer::exiter::exit_program("ERROR: Could not find file \"$filename\" !", "change_patchsequence_table"); }
-
- my $filecontent = installer::files::read_file($filename);
- my @newcontent = ();
-
- # Copying the header
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ ) { if ( $i < 3 ) { push(@newcontent, ${$filecontent}[$i]); } }
-
- # Syntax: PatchFamily Target Sequence Supersede
-
- my $patchfamily = "SO";
- my $target = "";
- my $patchsequence = get_patchsequence($allvariables);
- my $supersede = get_supersede($allvariables);
-
- if ( $#{$filecontent} >= 3 )
- {
- my $line = ${$filecontent}[3];
- if ( $line =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\s$/ )
- {
- $patchfamily = $1;
- $target = $2;
- }
- }
-
- #Adding sequence line, saving PatchFamily
- my $newline = "$patchfamily\t$target\t$patchsequence\t$supersede\n";
- push(@newcontent, $newline);
-
- # saving file
- installer::files::save_file($filename, \@newcontent);
-}
-
-####################################################################
-# Setting supersede, "0" for Hotfixes, "1" for ServicePack
-####################################################################
-
-sub get_supersede
-{
- my ( $allvariables ) = @_;
-
- my $supersede = 0; # if not defined, this is a Hotfix
-
- if (( $allvariables->{'SERVICEPACK'} ) && ( $allvariables->{'SERVICEPACK'} == 1 )) { $supersede = 1; }
-
- return $supersede;
-}
-
-####################################################################
-# Setting the sequence of the patch
-####################################################################
-
-sub get_patchsequence
-{
- my ( $allvariables ) = @_;
-
- my $patchsequence = "1.0";
-
- if ( ! $allvariables->{'PACKAGEVERSION'} ) { installer::exiter::exit_program("ERROR: PACKAGEVERSION must be set for msp patch creation!", "get_patchsequence"); }
-
- my $packageversion = $allvariables->{'PACKAGEVERSION'};
-
- if ( $packageversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ )
- {
- my $major = $1;
- my $minor = $2;
- my $micro = $3;
- my $concat = 100 * $minor + $micro;
- $packageversion = $major . "\." . $concat;
- }
- my $vendornumber = 0;
- if ( $allvariables->{'VENDORPATCHVERSION'} ) { $vendornumber = $allvariables->{'VENDORPATCHVERSION'}; }
- $patchsequence = $packageversion . "\." . $installer::globals::buildid . "\." . $vendornumber;
-
- if ( $allvariables->{'PATCHSEQUENCE'} ) { $patchsequence = $allvariables->{'PATCHSEQUENCE'}; }
-
- return $patchsequence;
-}
-
-####################################################################
-# Editing all tables from pcp file, that need to be edited
-####################################################################
-
-sub edit_tables
-{
- my ($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref) = @_;
-
- # table list contains: my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence";
-
- change_properties_table($localmspdir, $mspfilename);
- change_targetimages_table($localmspdir, $olddatabase);
- change_upgradedimages_table($localmspdir, $newdatabase);
- change_imagefamilies_table($localmspdir);
- change_patchmetadata_table($localmspdir, $allvariables, $languagestringref);
- change_patchsequence_table($localmspdir, $allvariables);
-}
-
-#################################################################################
-# Checking, if this is the correct database.
-#################################################################################
-
-sub correct_patch
-{
- my ($product, $pro, $langs, $languagestringref) = @_;
-
- my $correct_patch = 0;
-
- # Comparing $product with $installer::globals::product and
- # $pro with $installer::globals::pro and
- # $langs with $languagestringref
-
- my $product_is_good = 0;
-
- my $localproduct = $installer::globals::product;
- if ( $installer::globals::languagepack ) { $localproduct = $localproduct . "LanguagePack"; }
-
- if ( $product eq $localproduct ) { $product_is_good = 1; }
-
- if ( $product_is_good )
- {
- my $pro_is_good = 0;
-
- if ((( $pro eq "pro" ) && ( $installer::globals::pro )) || (( $pro eq "nonpro" ) && ( ! $installer::globals::pro ))) { $pro_is_good = 1; }
-
- if ( $pro_is_good )
- {
- my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ",");
- my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_");
-
- my $not_included = 0;
- foreach my $onelang ( keys %{$langlisthash} )
- {
- if ( ! exists($langstringhash->{$onelang}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included )
- {
- foreach my $onelanguage ( keys %{$langstringhash} )
- {
- if ( ! exists($langlisthash->{$onelanguage}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included ) { $correct_patch = 1; }
- }
- }
- }
-
- return $correct_patch;
-}
-
-#################################################################################
-# Searching for the path to the required patch for this special product.
-#################################################################################
-
-sub get_requiredpatchfile_from_list
-{
- my ($filecontent, $languagestringref, $filename) = @_;
-
- my $patchpath = "";
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- my $line = ${$filecontent}[$i];
- if ( $line =~ /^\s*$/ ) { next; } # empty line
- if ( $line =~ /^\s*\#/ ) { next; } # comment line
-
- if ( $line =~ /^\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*$/ )
- {
- my $product = $1;
- my $pro = $2;
- my $langs = $3;
- my $path = $4;
-
- 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"); }
-
- if ( correct_patch($product, $pro, $langs, $languagestringref) )
- {
- $patchpath = $path;
- last;
- }
- }
- else
- {
- installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_requiredpatchfile_from_list");
- }
- }
-
- return $patchpath;
-}
-
-##################################################################
-# Converting unicode file to ascii
-# to be more precise: uft-16 little endian to ascii
-##################################################################
-
-sub convert_unicode_to_ascii
-{
- my ( $filename ) = @_;
-
- my @localfile = ();
-
- my $savfilename = $filename . "_before.unicode";
- installer::systemactions::copy_one_file($filename, $savfilename);
-
-# open( IN, "<:utf16", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii");
-# open( IN, "<:para:crlf:uni", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii");
- open( IN, "<:encoding(UTF16-LE)", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii");
-# open( IN, "<:encoding(UTF-8)", $filename ) || installer::exiter::exit_program("ERROR: Cannot open file $filename for reading", "convert_unicode_to_ascii");
- while ( $line = <IN> ) {
- push @localfile, $line;
- }
- close( IN );
-
- if ( open( OUT, ">", $filename ) )
- {
- print OUT @localfile;
- close(OUT);
- }
-}
-
-####################################################################
-# Analyzing the log file created by msimsp.exe to find all
-# files included into the patch.
-####################################################################
-
-sub analyze_msimsp_logfile
-{
- my ($logfile, $filesarray) = @_;
-
- # Reading log file after converting from utf-16 (LE) to ascii
- convert_unicode_to_ascii($logfile);
- my $logfilecontent = installer::files::read_file($logfile);
-
- # Creating hash from $filesarray: unique file name -> destination of file
- my %filehash = ();
- my %destinationcollector = ();
-
- for ( my $i = 0; $i <= $#{$filesarray}; $i++ )
- {
- my $onefile = ${$filesarray}[$i];
-
- # Only collecting files with "uniquename" and "destination"
- if (( exists($onefile->{'uniquename'}) ) && ( exists($onefile->{'uniquename'}) ))
- {
- my $uniquefilename = $onefile->{'uniquename'};
- my $destpath = $onefile->{'destination'};
- $filehash{$uniquefilename} = $destpath;
- }
- }
-
- # Analyzing log file of msimsp.exe, finding all changed files
- # and searching all destinations of unique file names.
- # Content in log file: "INFO File Key: <file key> is modified"
- # Collecting content in @installer::globals::patchfilecollector
-
- for ( my $i = 0; $i <= $#{$logfilecontent}; $i++ )
- {
- if ( ${$logfilecontent}[$i] =~ /Key\:\s*(.*?) is modified\s*$/ )
- {
- my $filekey = $1;
- if ( exists($filehash{$filekey}) ) { $destinationcollector{$filehash{$filekey}} = 1; }
- else { installer::exiter::exit_program("ERROR: Could not find file key \"$filekey\" in file collector.", "analyze_msimsp_logfile"); }
- }
- }
-
- foreach my $onedest ( sort keys %destinationcollector ) { push(@installer::globals::patchfilecollector, "$onedest\n"); }
-
-}
-
-####################################################################
-# Creating msp patch files for Windows
-####################################################################
-
-sub create_msp_patch
-{
- my ($installationdir, $includepatharrayref, $allvariables, $languagestringref, $languagesarrayref, $filesarray) = @_;
-
- # print this message even in 'quiet' mode
- $installer::logger::Info->print("\n");
- $installer::logger::Info->print("******************************************\n");
- $installer::logger::Info->print("... creating msp installation set ...\n", 1);
- $installer::logger::Info->print("******************************************\n");
-
- $installer::globals::creating_windows_installer_patch = 1;
-
- my @needed_files = ("msimsp.exe"); # only required for patch creation process
- installer::control::check_needed_files_in_path(\@needed_files);
-
- installer::logger::include_header_into_logfile("Creating msp installation sets:");
-
- my $firstdir = $installationdir;
- installer::pathanalyzer::get_path_from_fullqualifiedname(\$firstdir);
-
- my $lastdir = $installationdir;
- installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$lastdir);
-
- if ( $lastdir =~ /\./ ) { $lastdir =~ s/\./_msp_inprogress\./ }
- else { $lastdir = $lastdir . "_msp_inprogress"; }
-
- # Removing existing directory "_native_packed_inprogress" and "_native_packed_witherror" and "_native_packed"
-
- my $mspdir = $firstdir . $lastdir;
- if ( -d $mspdir ) { installer::systemactions::remove_complete_directory($mspdir); }
-
- my $olddir = $mspdir;
- $olddir =~ s/_inprogress/_witherror/;
- if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
-
- $olddir = $mspdir;
- $olddir =~ s/_inprogress//;
- if ( -d $olddir ) { installer::systemactions::remove_complete_directory($olddir); }
-
- # Creating the new directory for new installation set
- installer::systemactions::create_directory($mspdir);
-
- $installer::globals::saveinstalldir = $mspdir;
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Starting product installation");
-
- # Installing both installation sets
- $installer::logger::Info->printf("... installing products ...\n");
- my ($olddatabase, $newdatabase) = install_installation_sets($installationdir);
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Starting synchronization of installation sets");
-
- # Synchronizing installed products, allowing only different files with PATCH flag
- $installer::logger::Info->printf("... synchronizing installation sets ...\n");
- synchronize_installation_sets($olddatabase, $newdatabase, $filesarray);
-
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Starting pcp file creation");
-
- # Create pcp file
- $installer::logger::Info->printf("... creating pcp file ...\n");
-
- my $localmspdir = installer::systemactions::create_directories("msp", $languagestringref);
-
- if ( ! $allvariables->{'PCPFILENAME'} ) { installer::exiter::exit_program("ERROR: Property \"PCPFILENAME\" has to be defined.", "create_msp_patch"); }
- my $pcpfilename = $allvariables->{'PCPFILENAME'};
-
- if ( $installer::globals::languagepack ) { $pcpfilename =~ s/.pcp\s*$/languagepack.pcp/; }
-
- # Searching the pcp file in the include pathes
- my $fullpcpfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$pcpfilename, $includepatharrayref, 1);
- if ( $$fullpcpfilenameref eq "" ) { installer::exiter::exit_program("ERROR: pcp file not found: $pcpfilename !", "create_msp_patch"); }
- my $fullpcpfilenamesource = $$fullpcpfilenameref;
-
- # Copying pcp file
- my $fullpcpfilename = $localmspdir . $installer::globals::separator . $pcpfilename;
- installer::systemactions::copy_one_file($fullpcpfilenamesource, $fullpcpfilename);
-
- # a. Extracting tables from msi database: msidb.exe -d <msifile> -f <directory> -e File Media, ...
- # b. Changing content of msi database in tables: File, Media, Directory, FeatureComponent
- # c. Including tables into msi database: msidb.exe -d <msifile> -f <directory> -i File Media, ...
-
- # Unpacking tables from pcp file
- extract_all_tables_from_pcpfile($fullpcpfilename, $localmspdir);
-
- # Tables, that need to be edited
- my $tablelist = "Properties TargetImages UpgradedImages ImageFamilies PatchMetadata PatchSequence"; # required tables
-
- # Saving all tables
- check_and_save_tables($tablelist, $localmspdir);
-
- # Setting the name of the new msp file
- my $mspfilename = set_mspfilename($allvariables, $mspdir, $languagesarrayref);
-
- # Editing tables
- edit_tables($tablelist, $localmspdir, $olddatabase, $newdatabase, $mspfilename, $allvariables, $languagestringref);
-
- # Adding edited tables into pcp file
- include_tables_into_pcpfile($fullpcpfilename, $localmspdir, $tablelist);
-
- # Start msimsp.exe
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Starting msimsp.exe");
- my $msimsplogfile = execute_msimsp($fullpcpfilename, $mspfilename, $localmspdir);
-
- # Copy final installation set next to msp file
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: Copying installation set");
- $installer::logger::Info->printf("... copying installation set ...\n");
-
- my $oldinstallationsetpath = $installer::globals::updatedatabasepath;
-
- if ( $^O =~ /cygwin/i ) { $oldinstallationsetpath =~ s/\\/\//g; }
-
- installer::pathanalyzer::get_path_from_fullqualifiedname(\$oldinstallationsetpath);
- installer::systemactions::copy_complete_directory($oldinstallationsetpath, $mspdir);
-
- # Copying additional patches into the installation set, if required
- if (( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ) && ( $allvariables->{'ADDITIONALREQUIREDPATCHES'} ne "" ) && ( ! $installer::globals::languagepack ))
- {
- my $filename = $allvariables->{'ADDITIONALREQUIREDPATCHES'};
-
- my $fullfilenameref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1);
- if ( $$fullfilenameref eq "" ) { installer::exiter::exit_program("ERROR: Could not find file with required patches, although it is defined: $filename !", "create_msp_patch"); }
- my $fullfilename = $$fullfilenameref;
-
- # Reading list file
- my $listfile = installer::files::read_file($fullfilename);
-
- # Get name and path of reference database
- my $requiredpatchfile = get_requiredpatchfile_from_list($listfile, $languagestringref, $fullfilename);
- 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"); }
-
- # Copying patch file
- installer::systemactions::copy_one_file($requiredpatchfile, $mspdir);
- # my $infoline = "Copy $requiredpatchfile to $mspdir\n";
- # $installer::logger::Lang->print($infoline);
- }
-
- # Find all files included into the patch
- # Analyzing the msimsp log file $msimsplogfile
- analyze_msimsp_logfile($msimsplogfile, $filesarray);
-
- # Done
- $installer::logger::Lang->print("\n");
- $installer::logger::Lang->add_timestamp("Performance Info: msp creation done");
-
- return $mspdir;
-}
-
-1;
diff --git a/solenv/bin/modules/installer/windows/property.pm b/solenv/bin/modules/installer/windows/property.pm
index eddce824633b..e93ad0491950 100644
--- a/solenv/bin/modules/installer/windows/property.pm
+++ b/solenv/bin/modules/installer/windows/property.pm
@@ -308,12 +308,6 @@ sub set_important_properties
$onepropertyline = "DONTOPTIMIZELIBS" . "\t" . "0" . "\n";
push(@{$propertyfile}, $onepropertyline);
- if ( $installer::globals::sundirexists )
- {
- my $onepropertyline = "SUNDIREXISTS" . "\t" . "1" . "\n";
- push(@{$propertyfile}, $onepropertyline);
- }
-
if ( $installer::globals::officedirhostname )
{
my $onepropertyline = "OFFICEDIRHOSTNAME" . "\t" . $installer::globals::officedirhostname . "\n";
@@ -325,12 +319,6 @@ sub set_important_properties
push(@{$propertyfile}, $onepropertyline);
}
- if ( $installer::globals::sundirhostname )
- {
- my $onepropertyline = "SUNDIRHOSTNAME" . "\t" . $installer::globals::sundirhostname . "\n";
- push(@{$propertyfile}, $onepropertyline);
- }
-
if ( $installer::globals::desktoplinkexists )
{
my $onepropertyline = "DESKTOPLINKEXISTS" . "\t" . "1" . "\n";
diff --git a/solenv/bin/modules/installer/windows/registry.pm b/solenv/bin/modules/installer/windows/registry.pm
index 3e26b03810d6..6469ee1b536a 100644
--- a/solenv/bin/modules/installer/windows/registry.pm
+++ b/solenv/bin/modules/installer/windows/registry.pm
@@ -77,17 +77,6 @@ sub get_registry_component_name
my $styles = "";
if ( $registryref->{'Styles'} ) { $styles = $registryref->{'Styles'}; }
- # Layer links must have unique Component GUID for all products. This is necessary, because only the
- # uninstallation of the last product has to delete registry keys.
- if ( $styles =~ /\bLAYER_REGISTRY\b/ )
- {
- $componentname = "g_m_root_registry_layer_ooo_reglayer";
- # Styles USE_URELAYERVERSION, USE_OOOBASEVERSION
- if ( $styles =~ /\bUSE_URELAYERVERSION\b/ ) { $addon = "_ure_" . $allvariables->{'URELAYERVERSION'}; }
- if ( $styles =~ /\bUSE_OOOBASEVERSION\b/ ) { $addon = "_basis_" . $allvariables->{'OOOBASEVERSION'}; }
- $addon =~ s/\.//g;
- }
-
$componentname = $componentname . $addon;
if (( $styles =~ /\bLANGUAGEPACK\b/ ) && ( $installer::globals::languagepack )) { $componentname = $componentname . "_lang"; }
diff --git a/solenv/bin/modules/installer/windows/update.pm b/solenv/bin/modules/installer/windows/update.pm
deleted file mode 100644
index 974ac6b760f8..000000000000
--- a/solenv/bin/modules/installer/windows/update.pm
+++ /dev/null
@@ -1,595 +0,0 @@
-#**************************************************************
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-#**************************************************************
-
-
-
-package installer::windows::update;
-
-use installer::converter;
-use installer::exiter;
-use installer::files;
-use installer::globals;
-use installer::pathanalyzer;
-use installer::systemactions;
-
-#################################################################################
-# Extracting all tables from an msi database
-#################################################################################
-
-sub extract_all_tables_from_msidatabase
-{
- my ($fulldatabasepath, $workdir) = @_;
-
- my $msidb = "msidb.exe"; # Has to be in the path
- my $infoline = "";
- my $systemcall = "";
- my $returnvalue = "";
- my $extraslash = ""; # Has to be set for non-ActiveState perl
-
- # Export of all tables by using "*"
-
- if ( $^O =~ /cygwin/i ) {
- # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
- $fulldatabasepath =~ s/\//\\\\/g;
- $workdir =~ s/\//\\\\/g;
- $extraslash = "\\";
- }
-
- $systemcall = $msidb . " -d " . $fulldatabasepath . " -f " . $workdir . " -e " . $extraslash . "*";
- $returnvalue = system($systemcall);
-
- $installer::logger::Lang->printf("Systemcall: %s\n", $systemcall);
-
- if ($returnvalue)
- {
- $installer::logger::Lang->printf("ERROR: Could not execute %s !\n", $systemcall);
- installer::exiter::exit_program("ERROR: Could not exclude tables from msi database: $fulldatabasepath !", "extract_all_tables_from_msidatabase");
- }
- else
- {
- $installer::logger::Lang->printf("Success: Executed %s successfully!\n", $systemcall);
- }
-}
-
-#################################################################################
-# Collecting the keys from the first line of the idt file
-#################################################################################
-
-sub collect_all_keys
-{
- my ($line) = @_;
-
- my @allkeys = ();
- my $rownumber = 0;
- my $onekey = "";
-
- while ( $line =~ /^\s*(\S+?)\t(.*)$/ )
- {
- $onekey = $1;
- $line = $2;
- $rownumber++;
- push(@allkeys, $onekey);
- }
-
- # and the last key
-
- $onekey = $line;
- $onekey =~ s/^\s*//g;
- $onekey =~ s/\s*$//g;
-
- $rownumber++;
- push(@allkeys, $onekey);
-
- return (\@allkeys, $rownumber);
-}
-
-#################################################################################
-# Analyzing the content of one line of an idt file
-#################################################################################
-
-sub get_oneline_hash
-{
- my ($line, $allkeys, $rownumber) = @_;
-
- my $counter = 0;
- my %linehash = ();
-
- $line =~ s/^\s*//;
- $line =~ s/\s*$//;
-
- my $value = "";
- my $onekey = "";
-
- while ( $line =~ /^(.*?)\t(.*)$/ )
- {
- $value = $1;
- $line = $2;
- $onekey = ${$allkeys}[$counter];
- $linehash{$onekey} = $value;
- $counter++;
- }
-
- # the last column
-
- $value = $line;
- $onekey = ${$allkeys}[$counter];
-
- $linehash{$onekey} = $value;
-
- return \%linehash;
-}
-
-#################################################################################
-# Analyzing the content of an idt file
-#################################################################################
-
-sub analyze_idt_file
-{
- my ($filecontent) = @_;
-
- my %table = ();
- # keys are written in first line
- my ($allkeys, $rownumber) = collect_all_keys(${$filecontent}[0]);
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- if (( $i == 0 ) || ( $i == 1 ) || ( $i == 2 )) { next; }
-
- my $onelinehash = get_oneline_hash(${$filecontent}[$i], $allkeys, $rownumber);
- my $linekey = $i - 2; # ! : The linenumber is the unique key !? Always decrease by two, because of removed first three lines.
- $table{$linekey} = $onelinehash;
- }
-
- return \%table;
-}
-
-#################################################################################
-# Reading all idt files in a specified directory
-#################################################################################
-
-sub read_all_tables_from_msidatabase
-{
- my ($workdir) = @_;
-
- my %database = ();
-
- my $ext = "idt";
-
- my $allidtfiles = installer::systemactions::find_file_with_file_extension($ext, $workdir);
-
- for ( my $i = 0; $i <= $#{$allidtfiles}; $i++ )
- {
- my $onefilename = ${$allidtfiles}[$i];
- my $longonefilename = $workdir . $installer::globals::separator . $onefilename;
- if ( ! -f $longonefilename ) { installer::exiter::exit_program("ERROR: Could not find idt file: $longonefilename!", "read_all_tables_from_msidatabase"); }
- my $filecontent = installer::files::read_file($longonefilename);
- my $idtcontent = analyze_idt_file($filecontent);
- my $key = $onefilename;
- $key =~ s/\.idt\s*$//;
- $database{$key} = $idtcontent;
- }
-
- return \%database;
-}
-
-#################################################################################
-# Checking, if this is the correct database.
-#################################################################################
-
-sub correct_database
-{
- my ($product, $pro, $langs, $languagestringref) = @_;
-
- my $correct_database = 0;
-
- # Comparing $product with $installer::globals::product and
- # $pro with $installer::globals::pro and
- # $langs with $languagestringref
-
- my $product_is_good = 0;
-
- my $localproduct = $installer::globals::product;
- if ( $installer::globals::languagepack ) { $localproduct = $localproduct . "LanguagePack"; }
-
- if ( $product eq $localproduct ) { $product_is_good = 1; }
-
- if ( $product_is_good )
- {
- my $pro_is_good = 0;
-
- if ((( $pro eq "pro" ) && ( $installer::globals::pro )) || (( $pro eq "nonpro" ) && ( ! $installer::globals::pro ))) { $pro_is_good = 1; }
-
- if ( $pro_is_good )
- {
- my $langlisthash = installer::converter::convert_stringlist_into_hash(\$langs, ",");
- my $langstringhash = installer::converter::convert_stringlist_into_hash($languagestringref, "_");
-
- my $not_included = 0;
- foreach my $onelang ( keys %{$langlisthash} )
- {
- if ( ! exists($langstringhash->{$onelang}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included )
- {
- foreach my $onelanguage ( keys %{$langstringhash} )
- {
- if ( ! exists($langlisthash->{$onelanguage}) )
- {
- $not_included = 1;
- last;
- }
- }
-
- if ( ! $not_included ) { $correct_database = 1; }
- }
- }
- }
-
- return $correct_database;
-}
-
-#################################################################################
-# Searching for the path to the reference database for this special product.
-#################################################################################
-
-sub get_databasename_from_list
-{
- my ($filecontent, $languagestringref, $filename) = @_;
-
- my $databasepath = "";
-
- for ( my $i = 0; $i <= $#{$filecontent}; $i++ )
- {
- my $line = ${$filecontent}[$i];
- if ( $line =~ /^\s*$/ ) { next; } # empty line
- if ( $line =~ /^\s*\#/ ) { next; } # comment line
-
- if ( $line =~ /^\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*\t+\s*(.+?)\s*$/ )
- {
- my $product = $1;
- my $pro = $2;
- my $langs = $3;
- my $path = $4;
-
- 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"); }
-
- if ( correct_database($product, $pro, $langs, $languagestringref) )
- {
- $databasepath = $path;
- last;
- }
- }
- else
- {
- installer::exiter::exit_program("ERROR: Wrong syntax in file: $filename! Line: \"$line\"", "get_databasename_from_list");
- }
- }
-
- return $databasepath;
-}
-
-#################################################################################
-# Reading an existing database completely
-#################################################################################
-
-sub readdatabase
-{
- my ($allvariables, $languagestringref, $includepatharrayref) = @_;
-
- my $database = "";
- my $infoline = "";
-
- if ( ! $allvariables->{'UPDATE_DATABASE_LISTNAME'} ) { installer::exiter::exit_program("ERROR: If \"UPDATE_DATABASE\" is set, \"UPDATE_DATABASE_LISTNAME\" is required.", "Main"); }
- my $listfilename = $allvariables->{'UPDATE_DATABASE_LISTNAME'};
-
- # Searching the list in the include pathes
- my $listname = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$listfilename, $includepatharrayref, 1);
- if ( $$listname eq "" ) { installer::exiter::exit_program("ERROR: List file not found: $listfilename !", "readdatabase"); }
- my $completelistname = $$listname;
-
- # Reading list file
- my $listfile = installer::files::read_file($completelistname);
-
- # Get name and path of reference database
- my $databasename = get_databasename_from_list($listfile, $languagestringref, $completelistname);
-
- # If the correct database was not found, this is not necessarily an error. But in this case, this is not an update packaging process!
- if (( $databasename ) && ( $databasename ne "" )) # This is an update packaging process!
- {
- $installer::globals::updatedatabase = 1;
- $installer::logger::Info->printf("... update process, using database %s ...\n", $databasename);
- $installer::logger::Lang->printf("\n");
- $installer::logger::Lang->printf("Database found in %s: \"%s\"\n", $completelistname, $databasename);
- $installer::logger::Lang->printf("\n");
- # Saving in global variable
- $installer::globals::updatedatabasepath = $databasename;
- }
- else
- {
- $installer::logger::Lang->printf("\n");
- $installer::logger::Lang->printf("No database found in %s. This is no update process!\n", $completelistname);
- $installer::logger::Lang->printf("\n");
- }
-
- if ( $installer::globals::updatedatabase )
- {
- if ( ! -f $databasename ) { installer::exiter::exit_program("ERROR: Could not find reference database: $databasename!", "readdatabase"); }
-
- my $msifilename = $databasename;
- installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$msifilename);
-
- $installer::logger::Lang->add_timestamp("Performance Info: readdatabase start");
-
- # create directory for unpacking
- my $databasedir = installer::systemactions::create_directories("database", $languagestringref);
-
- # copy database
- my $fulldatabasepath = $databasedir . $installer::globals::separator . $msifilename;
- installer::systemactions::copy_one_file($databasename, $fulldatabasepath);
-
- $installer::logger::Lang->add_timestamp("Performance Info: readdatabase: before extracting tables");
-
- # extract all tables from database
- extract_all_tables_from_msidatabase($fulldatabasepath, $databasedir);
-
- $installer::logger::Lang->add_timestamp("Performance Info: readdatabase: before reading tables");
-
- # read all tables
- $database = read_all_tables_from_msidatabase($databasedir);
-
- # Test output:
-
- # foreach my $key1 ( keys %{$database} )
- # {
- # print "Test1: $key1\n";
- # foreach my $key2 ( keys %{$database->{$key1}} )
- # {
- # print "\tTest2: $key2\n";
- # foreach my $key3 ( keys %{$database->{$key1}->{$key2}} )
- # {
- # print "\t\tTest3: $key3: $database->{$key1}->{$key2}->{$key3}\n";
- # }
- # }
- # }
-
- # Example: File table
-
- # my $filetable = $database->{'File'};
- # foreach my $linenumber ( keys %{$filetable} )
- # {
- # print "Test Filenumber: $linenumber\n";
- # foreach my $key ( keys %{$filetable->{$linenumber}} )
- # {
- # print "\t\tTest: $key: $filetable->{$linenumber}->{$key}\n";
- # }
- # }
-
- # Example: Searching for ProductCode in table Property
-
- # my $column1 = "Property";
- # my $column2 = "Value";
- # my $searchkey = "ProductCode";
- # my $propertytable = $database->{'Property'};
- # foreach my $linenumber ( keys %{$propertytable} )
- # {
- # if ( $propertytable->{$linenumber}->{$column1} eq $searchkey )
- # {
- # print("Test: $searchkey : $propertytable->{$linenumber}->{$column2}\n");
- # }
- # }
-
- $installer::logger::Lang->add_timestamp("Performance Info: readdatabase end");
- }
-
- return $database;
-}
-
-#################################################################################
-# Files can be included in merge modules. This is also important for update.
-#################################################################################
-
-sub readmergedatabase
-{
- my ( $mergemodules, $languagestringref, $includepatharrayref ) = @_;
-
- $installer::logger::Lang->add_timestamp("Performance Info: readmergedatabase start");
-
- my $mergemoduledir = installer::systemactions::create_directories("mergedatabase", $languagestringref);
-
- my %allmergefiles = ();
-
- $installer::globals::mergemodulenumber = $#{$mergemodules} + 1;
-
- foreach my $mergemodule ( @{$mergemodules} )
- {
- my $filename = $mergemodule->{'Name'};
- my $mergefile = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1);
-
- if ( $$mergefile eq "" ) { installer::exiter::exit_program("ERROR: msm file not found: $filename !", "readmergedatabase"); }
- my $completesource = $$mergefile;
-
- my $mergegid = $mergemodule->{'gid'};
- my $workdir = $mergemoduledir . $installer::globals::separator . $mergegid;
- if ( ! -d $workdir ) { installer::systemactions::create_directory($workdir); }
-
- my $completedest = $workdir . $installer::globals::separator . $filename;
- installer::systemactions::copy_one_file($completesource, $completedest);
- if ( ! -f $completedest ) { installer::exiter::exit_program("ERROR: msm file not found: $completedest !", "readmergedatabase"); }
-
- # extract all tables from database
- extract_all_tables_from_msidatabase($completedest, $workdir);
-
- # read all tables
- my $onemergefile = read_all_tables_from_msidatabase($workdir);
-
- $allmergefiles{$mergegid} = $onemergefile;
- }
-
- foreach my $mergefilegid ( keys %allmergefiles )
- {
- my $onemergefile = $allmergefiles{$mergefilegid};
- my $filetable = $onemergefile->{'File'};
-
- foreach my $linenumber ( keys %{$filetable} )
- {
- # Collecting all files from merge modules in global hash
- $installer::globals::mergemodulefiles{$filetable->{$linenumber}->{'File'}} = 1;
- }
- }
-
- $installer::logger::Lang->add_timestamp("Performance Info: readmergedatabase end");
-}
-
-#################################################################################
-# Creating several useful hashes from old database
-#################################################################################
-
-sub create_database_hashes
-{
- my ( $database ) = @_;
-
- # 1. Hash ( Component -> UniqueFileName ), required in File table.
- # Read from File table.
-
- my %uniquefilename = ();
- my %allupdatesequences = ();
- my %allupdatecomponents = ();
- my %allupdatefileorder = ();
- my %allupdatecomponentorder = ();
- my %revuniquefilename = ();
- my %revshortfilename = ();
- my %shortdirname = ();
- my %componentid = ();
- my %componentidkeypath = ();
- my %alloldproperties = ();
- my %allupdatelastsequences = ();
- my %allupdatediskids = ();
-
- my $filetable = $database->{'File'};
-
- foreach my $linenumber ( keys %{$filetable} )
- {
- my $comp = $filetable->{$linenumber}->{'Component_'};
- my $uniquename = $filetable->{$linenumber}->{'File'};
- my $filename = $filetable->{$linenumber}->{'FileName'};
- my $sequence = $filetable->{$linenumber}->{'Sequence'};
-
- my $shortname = "";
- if ( $filename =~ /^\s*(.*?)\|\s*(.*?)\s*$/ )
- {
- $shortname = $1;
- $filename = $2;
- }
-
- # unique is the combination of $component and $filename
- my $key = "$comp/$filename";
-
- if ( exists($uniquefilename{$key}) ) { installer::exiter::exit_program("ERROR: Component/FileName \"$key\" is not unique in table \"File\" !", "create_database_hashes"); }
-
- my $value = $uniquename;
- if ( $shortname ne "" ) { $value = "$uniquename;$shortname"; }
- $uniquefilename{$key} = $value; # saving the unique keys and short names in hash
-
- # Saving reverse keys too
- $revuniquefilename{$uniquename} = $key;
- if ( $shortname ne "" ) { $revshortfilename{$shortname} = $key; }
-
- # Saving Sequences for unique names (and also components)
- $allupdatesequences{$uniquename} = $sequence;
- $allupdatecomponents{$uniquename} = $comp;
-
- # Saving unique names and components for sequences
- $allupdatefileorder{$sequence} = $uniquename;
- $allupdatecomponentorder{$sequence} = $comp;
- }
-
- # 2. Hash, required in Directory table.
-
- my $dirtable = $database->{'Directory'};
-
- foreach my $linenumber ( keys %{$dirtable} )
- {
- my $dir = $dirtable->{$linenumber}->{'Directory'}; # this is a unique name
- my $defaultdir = $dirtable->{$linenumber}->{'DefaultDir'};
-
- my $shortname = "";
- if ( $defaultdir =~ /^\s*(.*?)\|\s*(.*?)\s*$/ )
- {
- $shortname = $1;
- $shortdirname{$dir} = $shortname; # collecting only the short names
- }
- }
-
- # 3. Hash, collecting info from Component table.
- # ComponentID and KeyPath have to be reused.
-
- my $comptable = $database->{'Component'};
-
- foreach my $linenumber ( keys %{$comptable} )
- {
- my $comp = $comptable->{$linenumber}->{'Component'};
- my $compid = $comptable->{$linenumber}->{'ComponentId'};
- my $keypath = $comptable->{$linenumber}->{'KeyPath'};
-
- $componentid{$comp} = $compid;
- $componentidkeypath{$comp} = $keypath;
- }
-
- # 4. Hash, property table, required for ProductCode and Installlocation.
-
- my $proptable = $database->{'Property'};
-
- foreach my $linenumber ( keys %{$proptable} )
- {
- my $prop = $proptable->{$linenumber}->{'Property'};
- my $value = $proptable->{$linenumber}->{'Value'};
-
- $alloldproperties{$prop} = $value;
- }
-
- # 5. Media table, getting last sequence
-
- my $mediatable = $database->{'Media'};
- $installer::globals::updatelastsequence = 0;
-
- foreach my $linenumber ( keys %{$mediatable} )
- {
- my $cabname = $mediatable->{$linenumber}->{'Cabinet'};
- my $lastsequence = $mediatable->{$linenumber}->{'LastSequence'};
- my $diskid = $mediatable->{$linenumber}->{'DiskId'};
- $allupdatelastsequences{$cabname} = $lastsequence;
- $allupdatediskids{$cabname} = $diskid;
-
- if ( $lastsequence > $installer::globals::updatelastsequence ) { $installer::globals::updatelastsequence = $lastsequence; }
- }
-
- $installer::globals::updatesequencecounter = $installer::globals::updatelastsequence;
-
- return (\%uniquefilename, \%revuniquefilename, \%revshortfilename, \%allupdatesequences, \%allupdatecomponents, \%allupdatefileorder, \%allupdatecomponentorder, \%shortdirname, \%componentid, \%componentidkeypath, \%alloldproperties, \%allupdatelastsequences, \%allupdatediskids);
-}
-
-
-1;
diff --git a/solenv/bin/modules/installer/ziplist.pm b/solenv/bin/modules/installer/ziplist.pm
index 6673c3236feb..7c66cdd6851c 100644
--- a/solenv/bin/modules/installer/ziplist.pm
+++ b/solenv/bin/modules/installer/ziplist.pm
@@ -30,6 +30,121 @@ use installer::logger;
use installer::parameter;
use installer::remover;
use installer::systemactions;
+use strict;
+
+=head2 read_openoffice_lst_file (#loggingdir)
+ Read the settings and variables from the settings file (typically 'openoffice.lst').
+=cut
+sub read_openoffice_lst_file ($$;$)
+{
+ my ($filename, $product_name, $loggingdir) = @_;
+
+ # Read all lines from the settings file.
+ my $ziplistref = installer::files::read_file($filename);
+
+ # Extract the lines of the settings block for the current product.
+ my ($productblockref, $parent) = installer::ziplist::getproductblock(
+ $ziplistref, $product_name, 1);
+ my ($settingsblockref, undef) = installer::ziplist::getproductblock($productblockref, "Settings", 0);
+ $settingsblockref = installer::ziplist::analyze_settings_block($settingsblockref);
+
+ # Split into settings and variables.
+ my $allsettingsarrayref = installer::ziplist::get_settings_from_ziplist($settingsblockref);
+ my $allvariablesarrayref = installer::ziplist::get_variables_from_ziplist($settingsblockref);
+
+ # global product block from zip.lst
+ my ($globalproductblockref, undef) = installer::ziplist::getproductblock(
+ $ziplistref, $installer::globals::globalblock, 0);
+
+ if ($installer::globals::globallogging && defined $loggingdir)
+ {
+ installer::files::save_file($loggingdir . "productblock.log", $productblockref);
+ installer::files::save_file($loggingdir . "settingsblock.log", $settingsblockref);
+ installer::files::save_file($loggingdir . "allsettings1.log", $allsettingsarrayref);
+ installer::files::save_file($loggingdir . "allvariables1.log", $allvariablesarrayref);
+ installer::files::save_file($loggingdir . "globalproductblock.log", $globalproductblockref);
+ }
+
+ # Integrate parent values.
+ while (defined $parent)
+ {
+ my $parentproductblockref;
+ ($parentproductblockref, $parent) = installer::ziplist::getproductblock($ziplistref, $parent, 1);
+ my ($parentsettingsblockref, undef) = installer::ziplist::getproductblock(
+ $parentproductblockref, "Settings", 0);
+ $parentsettingsblockref = installer::ziplist::analyze_settings_block($parentsettingsblockref);
+ my $allparentsettingsarrayref = installer::ziplist::get_settings_from_ziplist($parentsettingsblockref);
+ my $allparentvariablesarrayref = installer::ziplist::get_variables_from_ziplist($parentsettingsblockref);
+ if (scalar @$allparentsettingsarrayref > 0)
+ {
+ $allsettingsarrayref = installer::converter::combine_arrays_from_references_first_win(
+ $allsettingsarrayref,
+ $allparentsettingsarrayref)
+ }
+ if (scalar @$allparentvariablesarrayref)
+ {
+ $allvariablesarrayref = installer::converter::combine_arrays_from_references_first_win(
+ $allvariablesarrayref,
+ $allparentvariablesarrayref)
+ }
+ }
+
+ # Integrate global values.
+ if (scalar @$globalproductblockref)
+ {
+ # settings block from zip.lst
+ my ($globalsettingsblockref, undef) = installer::ziplist::getproductblock(
+ $globalproductblockref, "Settings", 0);
+
+ # select data from settings block in zip.lst
+ $globalsettingsblockref = installer::ziplist::analyze_settings_block($globalsettingsblockref);
+
+ my $allglobalsettingsarrayref = installer::ziplist::get_settings_from_ziplist($globalsettingsblockref);
+ my $allglobalvariablesarrayref = installer::ziplist::get_variables_from_ziplist($globalsettingsblockref);
+
+ if ($installer::globals::globallogging && defined $loggingdir)
+ {
+ installer::files::save_file($loggingdir . "globalsettingsblock1.log", $globalsettingsblockref);
+ installer::files::save_file($loggingdir . "globalsettingsblock2.log", $globalsettingsblockref);
+ installer::files::save_file($loggingdir . "allglobalsettings1.log", $allglobalsettingsarrayref);
+ installer::files::save_file($loggingdir . "allglobalvariables1.log", $allglobalvariablesarrayref);
+ }
+
+ if (scalar @$allglobalsettingsarrayref > 0)
+ {
+ $allsettingsarrayref = installer::converter::combine_arrays_from_references_first_win(
+ $allsettingsarrayref, $allglobalsettingsarrayref);
+ }
+ if (scalar @$allglobalvariablesarrayref > 0)
+ {
+ $allvariablesarrayref = installer::converter::combine_arrays_from_references_first_win(
+ $allvariablesarrayref, $allglobalvariablesarrayref);
+ }
+ }
+
+ # Remove multiples (and the trailing ##%##).
+ $allsettingsarrayref = installer::ziplist::remove_multiples_from_ziplist($allsettingsarrayref);
+ $allvariablesarrayref = installer::ziplist::remove_multiples_from_ziplist($allvariablesarrayref);
+ installer::ziplist::replace_variables_in_ziplist_variables($allvariablesarrayref);
+
+ # Transform array into hash.
+ my $allvariableshashref = installer::converter::convert_array_to_hash($allvariablesarrayref);
+
+ # Postprocess the variables.
+ installer::ziplist::set_default_productversion_if_required($allvariableshashref);
+ installer::ziplist::add_variables_to_allvariableshashref($allvariableshashref);
+ installer::ziplist::overwrite_ooovendor($allvariableshashref);
+
+ if ($installer::globals::globallogging && defined $loggingdir)
+ {
+ installer::files::save_file($loggingdir . "allsettings2.log" ,$allsettingsarrayref);
+ installer::files::save_file($loggingdir . "allvariables2.log" ,$allvariablesarrayref);
+ }
+
+ # Eventually we should fix this so that we don't have to return the raw arrays, only the resulting hashes.
+ return ($allvariableshashref, $allsettingsarrayref);
+}
+
#################################################
# Getting data from path file and zip list file
@@ -571,7 +686,7 @@ sub replace_languages_in_pathes
my $language = ${$languagesref}[$j];
$line =~ s/\$\(LANG\)/$language/g;
push(@patharray ,$line);
- $newdir = $line;
+ my $newdir = $line;
$line = $originalline;
installer::remover::remove_leading_and_ending_whitespaces(\$newline);
@@ -627,8 +742,6 @@ sub list_all_files_from_include_path
}
$installer::logger::Lang->print("\n");
-
- return \@filesarray;
}
#####################################################
@@ -780,9 +893,18 @@ sub add_variables_to_allvariableshashref
$variableshashref->{'LCPRODUCTEXTENSION'} = "";
}
- if ( $installer::globals::patch ) { $variableshashref->{'PRODUCTADDON'} = $installer::globals::patchaddon; }
- elsif ( $installer::globals::languagepack ) { $variableshashref->{'PRODUCTADDON'} = $installer::globals::languagepackaddon; }
- else { $variableshashref->{'PRODUCTADDON'} = ""; }
+ if ($installer::globals::patch)
+ {
+ $variableshashref->{'PRODUCTADDON'} = $installer::globals::patchaddon;
+ }
+ elsif ($installer::globals::languagepack)
+ {
+ $variableshashref->{'PRODUCTADDON'} = $installer::globals::languagepackaddon;
+ }
+ else
+ {
+ $variableshashref->{'PRODUCTADDON'} = "";
+ }
my $localbuild = $installer::globals::build;
if ( $localbuild =~ /^\s*(\w+?)(\d+)\s*$/ ) { $localbuild = $2; } # using "680" instead of "src680"
diff --git a/solenv/bin/modules/par2script/globals.pm b/solenv/bin/modules/par2script/globals.pm
index dc52b98d03a5..ecc2976f65f3 100644
--- a/solenv/bin/modules/par2script/globals.pm
+++ b/solenv/bin/modules/par2script/globals.pm
@@ -39,8 +39,7 @@ BEGIN
@allitems = ("Installation", "ScpAction", "Directory", "File",
"Shortcut", "Unixlink", "Module", "Profile", "ProfileItem",
- "Folder", "FolderItem", "RegistryItem", "WindowsCustomAction",
- "MergeModule");
+ "Folder", "FolderItem", "RegistryItem", "WindowsCustomAction");
@items_assigned_at_modules = ("File", "Directory", "Unixlink");
@items_with_directories = ("File", "Profile", "Shortcut", "Unixlink");
diff --git a/solenv/bin/modules/pre2par/globals.pm b/solenv/bin/modules/pre2par/globals.pm
index 6eb5b3d1146e..11e4544c1321 100644
--- a/solenv/bin/modules/pre2par/globals.pm
+++ b/solenv/bin/modules/pre2par/globals.pm
@@ -38,8 +38,7 @@ BEGIN
@allitems = ("Installation", "ScpAction", "HelpText", "Directory", "DataCarrier", "StarRegistry", "File",
"Shortcut", "Custom", "Unixlink", "Procedure", "Module", "Profile", "ProfileItem",
- "Folder", "FolderItem", "RegistryItem", "StarRegistryItem", "WindowsCustomAction",
- "MergeModule");
+ "Folder", "FolderItem", "RegistryItem", "StarRegistryItem", "WindowsCustomAction");
$logging = 0;
$logfilename = "logfile.log"; # the default logfile name for global errors