[Libreoffice-commits] core.git: Branch 'aoo/trunk' - 5 commits - instsetoo_native/data instsetoo_native/util scp2/source setup_native/source solenv/bin

Andre Fischer af at apache.org
Tue Nov 12 06:08:47 PST 2013


 instsetoo_native/data/releases.xml                     |  316 +++
 instsetoo_native/util/openoffice.lst                   |    2 
 scp2/source/ooo/mergemodules_ooo.scp                   |   52 
 setup_native/source/packinfo/finals_instsetoo.txt      |   35 
 solenv/bin/make_installer.pl                           |   58 
 solenv/bin/modules/installer/globals.pm                |   14 
 solenv/bin/modules/installer/patch/FileOperations.pm   |  333 +++
 solenv/bin/modules/installer/patch/FileSequenceList.pm |  159 +
 solenv/bin/modules/installer/patch/InstallationSet.pm  |  467 ++++
 solenv/bin/modules/installer/patch/Msi.pm              |  342 +++
 solenv/bin/modules/installer/patch/MsiRow.pm           |  160 +
 solenv/bin/modules/installer/patch/MsiTable.pm         |  274 ++
 solenv/bin/modules/installer/patch/ReleasesList.pm     |  210 ++
 solenv/bin/modules/installer/patch/Tools.pm            |   47 
 solenv/bin/modules/installer/patch/Version.pm          |   74 
 solenv/bin/modules/installer/windows/component.pm      |    5 
 solenv/bin/modules/installer/windows/directory.pm      |    9 
 solenv/bin/modules/installer/windows/file.pm           |  193 -
 solenv/bin/modules/installer/windows/media.pm          |  106 -
 solenv/bin/modules/installer/windows/mergemodule.pm    | 1668 -----------------
 solenv/bin/modules/installer/windows/msiglobal.pm      |  279 --
 solenv/bin/modules/installer/windows/msp.pm            | 1493 ---------------
 solenv/bin/modules/installer/windows/update.pm         |  595 ------
 solenv/bin/modules/par2script/globals.pm               |    3 
 solenv/bin/modules/pre2par/globals.pm                  |    3 
 solenv/bin/patch_make_releases_xml.pl                  |  197 ++
 solenv/bin/release_prepare.pl                          |  226 ++
 27 files changed, 2820 insertions(+), 4500 deletions(-)

New commits:
commit 1a43068abda6e8f4eb006d5adb18dc0793e513c9
Author: Andre Fischer <af at apache.org>
Date:   Tue Nov 12 13:49:49 2013 +0000

    123531: Added some new files (scripts and modules) for creating patches.

diff --git a/instsetoo_native/data/releases.xml b/instsetoo_native/data/releases.xml
new file mode 100644
index 0000000..34c4d07
--- /dev/null
+++ b/instsetoo_native/data/releases.xml
@@ -0,0 +1,316 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--***********************************************************
+ *
+ * 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.
+ *
+ ***********************************************************-->
+<releases>
+  <release>
+    <version>4.0.0</version>
+    <download>
+      <package-format>msi</package-format>
+      <url-template>
+        http://archive.apache.org/dist/openoffice/4.0.0/binaries/%L/Apache_OpenOffice_4.0.0_Win_x86_install_%L.exe
+      </url-template>
+      <item>
+        <language>ast</language>
+        <checksum type="sha256">415e2f3cf4d99a3f6ad495e33b89c716ef6966c9c4d7df90ad6e004fcf0222f4</checksum>
+        <size>154219869</size>
+      </item>
+      <item>
+        <language>cs</language>
+        <checksum type="sha256">a90a2c00c58f3e30654b89b4a363b099b0a7d1f829ebf9c7c18333d387f4bf41</checksum>
+        <size>130773239</size>
+      </item>
+      <item>
+        <language>de</language>
+        <checksum type="sha256">5569634ac40b42a710c666d0511f6aa4dbcb05d1a525e06f6be038e828c507f0</checksum>
+        <size>162401424</size>
+      </item>
+      <item>
+        <language>el</language>
+        <checksum type="sha256">cc5cde6314cea634200da6861da527c11ca7d74338074cdd4e5a22e1ffd9ef7c</checksum>
+        <size>139633387</size>
+      </item>
+      <item>
+        <language>en-GB</language>
+        <checksum type="sha256">7f83397877b72e7f2da38f11b76c3f46e30b93713b40becba699d21f913847e0</checksum>
+        <size>136201626</size>
+      </item>
+      <item>
+        <language>en-US</language>
+        <checksum type="sha256">8db246183f549c298d731cf61771f8f8adb37028d8ecc737fe1ad452899adb2d</checksum>
+        <size>143436858</size>
+      </item>
+      <item>
+        <language>es</language>
+        <checksum type="sha256">eb991c71b436c4d740f3d2b5441716fc321bb57eb7f36c7019ec86feebb7f5d4</checksum>
+        <size>132424454</size>
+      </item>
+      <item>
+        <language>fi</language>
+        <checksum type="sha256">fa2b9015864651be44afc940988ed20c6093bc8707aea72ab1b75cf147d81ed2</checksum>
+        <size>138474963</size>
+      </item>
+      <item>
+        <language>fr</language>
+        <checksum type="sha256">b4b20eac7f6220a4a6250e79d950a328d08b927b8856d762b0b1e033833e198f</checksum>
+        <size>133397214</size>
+      </item>
+      <item>
+        <language>gd</language>
+        <checksum type="sha256">c2e5ac75f899efab61f039a193a68ec2f4d092fd43c6eb46d8b2d34d8166ce6e</checksum>
+        <size>154472734</size>
+      </item>
+      <item>
+        <language>gl</language>
+        <checksum type="sha256">bac4915fd47b9e219d72a02a268fa590096c0884ebafd966b10e9b77fe16eee0</checksum>
+        <size>137952793</size>
+      </item>
+      <item>
+        <language>hu</language>
+        <checksum type="sha256">2e01d00431692cb6071cf520e71b900dba28a846dccf4ed3a85c245761c98906</checksum>
+        <size>133240224</size>
+      </item>
+      <item>
+        <language>it</language>
+        <checksum type="sha256">8663c01de8f62b26a7864ac4da6abd316a1c2e00b35c60372cad5287120fe409</checksum>
+        <size>138823014</size>
+      </item>
+      <item>
+        <language>ja</language>
+        <checksum type="sha256">559f165ee9ff516a80573befaf7d0936ca81fa89aca655213b4f265eb7c7059a</checksum>
+        <size>136416679</size>
+      </item>
+      <item>
+        <language>ko</language>
+        <checksum type="sha256">daa7f3b51e6ffb0b541a98fbcdc0bad53eea579a7d74c9acbdd73ad660b117b1</checksum>
+        <size>131617051</size>
+      </item>
+      <item>
+        <language>nl</language>
+        <checksum type="sha256">fcc6e55c7a1407be8e8f2faf7305ebb9a8f7e1bea882e5d917b5846a2c0ee955</checksum>
+        <size>138526756</size>
+      </item>
+      <item>
+        <language>pt</language>
+        <checksum type="sha256">58307e0eeb485840e1462a23f8741e793422ccdc468123f85876ae287482a987</checksum>
+        <size>130929247</size>
+      </item>
+      <item>
+        <language>pt-BR</language>
+        <checksum type="sha256">08ef83f28e138dc0bc6bdf761e4676eb13c2b30717ce47e0becec2de90c73f7a</checksum>
+        <size>130814647</size>
+      </item>
+      <item>
+        <language>ru</language>
+        <checksum type="sha256">dda689b273eb9ddadfb156a08df8e73c3b41e3cc8178a16546e282f8e1c54d77</checksum>
+        <size>137558077</size>
+      </item>
+      <item>
+        <language>sk</language>
+        <checksum type="sha256">d2722d2569178838a57705e76062603f995f71d5219e8f910bc7a6b46fa6039a</checksum>
+        <size>131199460</size>
+      </item>
+      <item>
+        <language>sl</language>
+        <checksum type="sha256">eecea1c75833a873a3cc00f81c85f411319b085728224c716ac90159622c0c3e</checksum>
+        <size>132340393</size>
+      </item>
+      <item>
+        <language>ta</language>
+        <checksum type="sha256">4051b4831a960a8f27a3f56f32d7bd5a7bbdfcf859238a149aca9cd69ae0121c</checksum>
+        <size>136961005</size>
+      </item>
+      <item>
+        <language>zh-CN</language>
+        <checksum type="sha256">94424b9c24d3237e70d6452da8366cf9c6617a46fa171901db093b1a1166934d</checksum>
+        <size>131840961</size>
+      </item>
+    </download>
+  </release>
+  <release>
+    <version>4.0.1</version>
+    <download>
+      <package-format>msi</package-format>
+      <url-template>
+        http://archive.apache.org/dist/openoffice/4.0.1/binaries/%L/Apache_OpenOffice_4.0.1_Win_x86_install_%L.exe
+      </url-template>
+      <item>
+    <language>ast</language>
+    <checksum type="sha256">9854b6a99c6e56902e30ec01009e294aafe091e4733e9b8933690ee0365d6754</checksum>
+    <size>154320289</size>
+      </item>
+      <item>
+    <language>cs</language>
+    <checksum type="sha256">b23c5dc07a6e521a7ad24e7c1d131c96ea3a6fdf3a2f96020b5cad2e7ebe0253</checksum>
+    <size>130785256</size>
+      </item>
+      <item>
+    <language>de</language>
+    <checksum type="sha256">fbbe39def767e6ecd16c7b6802f35d6e4b035c4b72328bbf0a8f045cf585aaa7</checksum>
+    <size>163606685</size>
+      </item>
+      <item>
+    <language>el</language>
+    <checksum type="sha256">e59f47b986c4bcd8f21062446b299f68ac7ed941356813b0e2dbd651fb59c847</checksum>
+    <size>139717373</size>
+      </item>
+      <item>
+    <language>en-GB</language>
+    <checksum type="sha256">75f06dbe9f13804ea9f3ef20d831e300a55df1bf1a5b656d2422206a8a0d8bda</checksum>
+    <size>136295104</size>
+      </item>
+      <item>
+    <language>en-US</language>
+    <checksum type="sha256">3b68145a33fa83d246febb3b7551fb0cbf57363bc772401ac0c37cfc1cde21b3</checksum>
+    <size>143485940</size>
+      </item>
+      <item>
+    <language>es</language>
+    <checksum type="sha256">5136276a370378d11327b9a0bd074d269a49e797c7186f2e3cc9cf6c0bbc20fc</checksum>
+    <size>132478227</size>
+      </item>
+      <item>
+    <language>eu</language>
+    <checksum type="sha256">aae1ff61af9ac117637842ccc1c28221620c79b05ffbb1fb47d8a6fcbe3b1700</checksum>
+    <size>131476228</size>
+      </item>
+      <item>
+    <language>fi</language>
+    <checksum type="sha256">65ff3209a51afefde11dd1326921340ebe035f09626d8884f37a0f72f8c2785b</checksum>
+    <size>138523539</size>
+      </item>
+      <item>
+    <language>fr</language>
+    <checksum type="sha256">70c97dc59412a8e4aeb87e51e8714cbba776397beb6a774804591653150e78d5</checksum>
+    <size>134622711</size>
+      </item>
+      <item>
+    <language>gd</language>
+    <checksum type="sha256">a57115a636f4004de2df9599e72bc4d07937b65a6bb99fe126dc18a788a57142</checksum>
+    <size>154574682</size>
+      </item>
+      <item>
+    <language>gl</language>
+    <checksum type="sha256">4c8fe9b42193dc37dc6a2b979b790ea6317ea25a6fa27fcb9007036c5725111d</checksum>
+    <size>138019151</size>
+      </item>
+      <item>
+    <language>hu</language>
+    <checksum type="sha256">97765ef536ed1e3f07220fe4cb90520efdfb376fab751ad2cac7390316f14e65</checksum>
+    <size>133302800</size>
+      </item>
+      <item>
+    <language>it</language>
+    <checksum type="sha256">c6fa3e0e9bef615d804b5d24d3f2cc49f7655aee01ef34cecb9b520a47249d02</checksum>
+    <size>138894766</size>
+      </item>
+      <item>
+    <language>ja</language>
+    <checksum type="sha256">93d20ae5f96f4a93c705894849f01b6501604bf003e9b66f7d0dbdc6f2282965</checksum>
+    <size>136444096</size>
+      </item>
+      <item>
+    <language>km</language>
+    <checksum type="sha256">4fc263c631d4ba797633d28ca529202b600d5fe676a8c215904d12d08ed8cc49</checksum>
+    <size>151866955</size>
+      </item>
+      <item>
+    <language>ko</language>
+    <checksum type="sha256">2abd13afe2978c4300d872a06dcec00ae23592ed563be3d0d046ef81738d7a87</checksum>
+    <size>131671507</size>
+      </item>
+      <item>
+    <language>lt</language>
+    <checksum type="sha256">4ac6c2c88edb5254e0cf93f49daaf5e411ea0168d6c431d11da5d89638977cff</checksum>
+    <size>136935582</size>
+      </item>
+      <item>
+    <language>nl</language>
+    <checksum type="sha256">85292dad5aa80711c126091d3565dc9cd2219d818a59cbd5c7c9a4bc5282ebb8</checksum>
+    <size>139734741</size>
+      </item>
+      <item>
+    <language>pl</language>
+    <checksum type="sha256">c71c63d0c0e76f28b7d3bebb39e1cb9c0ca35e29557c53528f631e6c1aeca04c</checksum>
+    <size>133661993</size>
+      </item>
+      <item>
+    <language>pt-BR</language>
+    <checksum type="sha256">e6baed3d30d4b18e32e21ab4fcd22446ac1f8a40efe49a4f105e9c3fc0ba1611</checksum>
+    <size>130866989</size>
+      </item>
+      <item>
+    <language>pt</language>
+    <checksum type="sha256">dd855dc99fc41fd509e938881397798fa2e9ed92e663cb8b9ea6c356d5d5a096</checksum>
+    <size>130989882</size>
+      </item>
+      <item>
+    <language>ru</language>
+    <checksum type="sha256">7e965822f8dfb0aa4a67bf5bff8ddb852901c672886bb9f2ee275c5c976c0a48</checksum>
+    <size>137584051</size>
+      </item>
+      <item>
+    <language>sk</language>
+    <checksum type="sha256">4400eb30ca5072b175da7963049bb0ecca761af73b7dbccb9a0b4cd789b26042</checksum>
+    <size>131265676</size>
+      </item>
+      <item>
+    <language>sl</language>
+    <checksum type="sha256">83d384d9e50ddcb9c1d74069d8796e5f37bed55b5da6f43c326c0784a6e61cef</checksum>
+    <size>132368586</size>
+      </item>
+      <item>
+    <language>sr</language>
+    <checksum type="sha256">a2d2e043c1c3fa9a90924ae29138641b238d7749984f873a8672e2844a55e3d9</checksum>
+    <size>136961170</size>
+      </item>
+      <item>
+    <language>sv</language>
+    <checksum type="sha256">15cbdb4f5a7ecf253f31981d0203c08e279a26603ca737e64f740524e1d672ca</checksum>
+    <size>131330363</size>
+      </item>
+      <item>
+    <language>ta</language>
+    <checksum type="sha256">352083d6d2fc6c39027a03fbbb6449d4a67955b370c5a8efba0407b74a456bc9</checksum>
+    <size>137001517</size>
+      </item>
+      <item>
+    <language>tr</language>
+    <checksum type="sha256">bdfbf83cc905bf44f086ea51295899a042667fa6334e6378ef5b5b354843ba37</checksum>
+    <size>130397087</size>
+      </item>
+      <item>
+    <language>vi</language>
+    <checksum type="sha256">0483c20036f47738ae86a19d0ab4e66eff8d8f5226f716970a4ec7f56a78bff6</checksum>
+    <size>131526617</size>
+      </item>
+      <item>
+    <language>zh-CN</language>
+    <checksum type="sha256">f2966f3c251cf31a24d7931950838c04e410935dd15a6fdd9241acf81bc5e784</checksum>
+    <size>131863915</size>
+      </item>
+      <item>
+    <language>zh-TW</language>
+    <checksum type="sha256">a194cfb2dc2cbcae2e89740485ebfcbf605b7c80a5bbdffb699e447c53698e53</checksum>
+    <size>131990994</size>
+      </item>
+    </download>
+  </release>
+</releases>
\ No newline at end of file
diff --git a/solenv/bin/modules/installer/patch/FileOperations.pm b/solenv/bin/modules/installer/patch/FileOperations.pm
new file mode 100644
index 0000000..931db2e
--- /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 0000000..6c607d8
--- /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 0000000..67ff1fe
--- /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 0000000..c5c650a
--- /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 0000000..24a6fd2
--- /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 0000000..a95b94a
--- /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 0000000..320e864
--- /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 0000000..b29b559
--- /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 0000000..685df6d
--- /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/patch_make_releases_xml.pl b/solenv/bin/patch_make_releases_xml.pl
new file mode 100644
index 0000000..b75046b
--- /dev/null
+++ b/solenv/bin/patch_make_releases_xml.pl
@@ -0,0 +1,197 @@
+#!/usr/bin/perl -w
+
+#**************************************************************
+#
+#  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.
+#
+#**************************************************************
+
+use LWP::UserAgent;
+
+use strict;
+
+=head1 NAME
+
+    patch_make_releases_xml.pl - Create a section for the instsetoo_native/data/releases.xml file.
+
+=head1 SYNOPSIS
+
+    patch_make_releases_xml.pl <version-number>
+
+        version-number is the version number (eg 4.0.1) for which to create the releases.xml file.
+
+=head1 DESCRIPTION
+
+    Will contact http://archive.apache.org/dist/openoffice/<version-number>/binaries/ and
+    a) determine the set of languages
+    b) collect sizes and sha256 check sums for all Windows installation sets.
+
+    The result is printed to the console.  It has to be added manually to releases.xml.
+
+=cut
+
+
+if (scalar @ARGV != 1)
+{
+    print STDERR "usage: $0 <version-number>\n";
+    die;
+}
+
+my $version = $ARGV[0];
+
+print <<EOT;
+<?xml version='1.0' encoding='UTF-8'?>
+<!--***********************************************************
+ *
+ * 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.
+ *
+ ***********************************************************-->
+EOT
+
+sub DownloadFile ($)
+{
+    my $url = shift;
+
+    my $agent = LWP::UserAgent->new();
+    $agent->timeout(120);
+    $agent->show_progress(0);
+
+    my $file_content = "";
+    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.
+        $file_content = "";
+            }
+            my($response,$agent,$h,$data)=@_;
+        $file_content .= $data;
+        });
+    $agent->get($url);
+
+    return $file_content;
+}
+
+
+
+
+sub GetResponse ($)
+{
+    my $url = shift;
+
+    my $agent = LWP::UserAgent->new();
+    $agent->timeout(120);
+    $agent->show_progress(0);
+
+    my $file_content = "";
+    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.
+        $file_content = "";
+            }
+            my($response,$agent,$h,$data)=@_;
+        $file_content .= $data;
+        });
+    return $agent->get($url, 'Range' => "bytes=0-0");
+}
+
+my @languages = ();
+my @lines = split(/\n/, DownloadFile("http://archive.apache.org/dist/openoffice/".$version."/binaries/"));
+foreach my $line (@lines)
+{
+    next unless $line =~ /folder.gif/;
+    if ($line =~ /a href=\"([^\"\/]+)\/\"/)
+    {
+    my $language = $1;
+    next if $language eq "SDK";
+    next if $language =~ /^[A-Z]/;
+    push @languages, $language;
+    }
+}
+
+print "<releases>\n";
+print "  <release>\n";
+printf "    <version>%s</version>\n", $version;
+print "    <download>\n";
+print "      <package-format>msi</package-format>\n";
+print "      <url-template>\n";
+printf "        http://archive.apache.org/dist/openoffice/%s/binaries/%%L/Apache_OpenOffice_%s_Win_x86_install_%%L.exe\n",$version, $version;
+print "      </url-template>\n";
+foreach my $language (sort @languages)
+{
+    print "      <item>\n";
+    printf "        <language>%s</language>\n", $language;
+    my $name = sprintf(
+    "Apache_OpenOffice_%s_Win_x86_install_%s.exe",
+    $version,
+    $language,
+    $version,
+    $language);
+
+    my $content = DownloadFile(
+    sprintf("http://archive.apache.org/dist/openoffice/%s/binaries/%s/%s.sha256", $version, $language, $name));
+    if ($content =~ /^([a-f0-9]+)/)
+    {
+    printf("        <checksum type=\"sha256\">%s</checksum>\n", $1);
+    }
+    my $response = GetResponse(
+    sprintf("http://archive.apache.org/dist/openoffice/%s/binaries/%s/%s", $version, $language, $name));
+    my $content_range = $response->{'_headers'}->{'content-range'};
+    if ($content_range =~ /bytes 0-0\/(\d+)/)
+    {
+    printf("        <size>%s</size>\n", $1);
+    }
+    print "      </item>\n";
+}
+
+print "    </download>\n";
+print "  </release>\n";
+print "</releases>\n";
diff --git a/solenv/bin/release_prepare.pl b/solenv/bin/release_prepare.pl
new file mode 100644
index 0000000..129358a
--- /dev/null
+++ b/solenv/bin/release_prepare.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+
+#**************************************************************
+#
+#  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.
+#
+#**************************************************************
+
+use lib ("$ENV{SOLARENV}/bin/modules");
+use installer::patch::InstallationSet;
+use installer::patch::Msi;
+use installer::patch::ReleasesList;
+use installer::ziplist;
+use installer::logger;
+
+use Getopt::Long;
+use Pod::Usage;
+use Digest;
+
+use strict;
+
+=head1 NAME
+
+    release_prepare.pl - Several functions to prepare release builds
+
+=head1 SYNOPSIS
+
+    release_prepare.pl [options] <language1> <language2> ...
+
+    Options:
+        --lst-file <filename>
+             Path to the .lst file, eg ../util/openoffice.lst
+        --product-name <product-name>
+             The product name, eg Apache_OpenOffice
+        --output-path <path>
+             Path to the instsetoo_native platform output tree
+        --source-version <major>.<minor>.<micro>
+             Override version number of the source.  If not given it is computed from the target version.
+
+=head1 DESCRIPTION
+
+    Prepare a release build:
+
+        - Provide installation sets of the previous version.
+          If they are not in ext_sources/ then they are downloaded.
+
+        - Unpack the installation sets.
+
+=cut
+
+
+sub ProcessCommandline ()
+{
+    my $arguments = {
+        'lst-file' => undef,
+        'product-name' => undef,
+        'output-path' => undef,
+        'source-version' => undef};
+
+    if ( ! GetOptions(
+               "lst-file=s", \$arguments->{'lst-file'},
+               "product-name=s", \$arguments->{'product-name'},
+               "output-path=s", \$arguments->{'output-path'},
+               "source-version:s" => \$arguments->{'source-version'}
+        ))
+    {
+        pod2usage(1);
+    }
+
+    if ( ! defined $arguments->{'lst-file'})
+    {
+        print STDERR "lst-file missing, please provide --lst-file\n";
+        pod2usage(2);
+    }
+    if ( ! defined $arguments->{'product-name'})
+    {
+        print STDERR "product name missing, please provide --product-name\n";
+        pod2usage(2);
+    }
+    if ( ! defined $arguments->{'output-path'})
+    {
+        print STDERR "output path missing, please provide --output-path\n";
+        pod2usage(2);
+    }
+
+    $arguments->{'languages'} = \@ARGV;
+
+    return $arguments;
+}
+
+
+
+
+sub ProcessLanguage ($$$$)
+{
+    my ($source_version, $language, $package_format, $product_name) = @_;
+
+    $installer::logger::Info->printf("%s\n", $language);
+    $installer::logger::Info->increase_indentation();
+
+    # For every language we need
+    # 1. have downloadable installation set available (download if missing)
+    # 2. unpack it to get access to .cab and .msi
+    # 3. unpack .cab so that msimsp.exe can be run
+
+    # Create paths to unpacked contents of .exe and .cab and determine if they exist.
+    # The existence of these paths is taken as flag whether the unpacking has already taken place.
+    my $unpacked_exe_path = installer::patch::InstallationSet::GetUnpackedMsiPath(
+        $source_version,
+        $language,
+        $package_format,
+        $product_name);
+    my $unpacked_cab_path = installer::patch::InstallationSet::GetUnpackedCabPath(
+        $source_version,
+        $language,
+        $package_format,
+        $product_name);
+    my $exe_is_unpacked = -d $unpacked_exe_path;
+    my $cab_is_unpacked = -d $unpacked_cab_path;
+
+    if ( ! $exe_is_unpacked)
+    {
+        # Interpret existence of path as proof that the installation
+        # set and the cab file have been successfully unpacked.
+        # Nothing to do.
+        my $filename = installer::patch::InstallationSet::ProvideDownloadSet(
+            $source_version,
+            $language,
+            $package_format);
+        if (defined $filename)
+        {
+            if ( ! -d $unpacked_exe_path)
+            {
+                installer::patch::InstallationSet::UnpackExe($filename, $unpacked_exe_path);
+            }
+        }
+        else
+        {
+            installer::logger::PrintError("could not provide .exe installation set at '%s'\n", $filename);
+        }
+    }
+    else
+    {
+        $installer::logger::Info->printf("downloadable installation set has already been unpacked to '%s'\n",
+            $unpacked_exe_path);
+    }
+
+    if ( ! $cab_is_unpacked)
+    {
+        my $cab_filename = File::Spec->catfile($unpacked_exe_path, "openoffice1.cab");
+        if ( ! -f $cab_filename)
+        {
+             # Cab file does not exist.
+            installer::logger::PrintError(
+                "could not find .cab file at '%s'.  Extraction of .exe seems to have failed.\n",
+                $cab_filename);
+        }
+
+        # Unpack the cab file.
+        my $msi = new installer::patch::Msi(
+            $source_version,
+            $language,
+            $product_name);
+
+        $installer::logger::Info->printf("unpacking cab file '%s' to '%s'\n",
+            $cab_filename, $unpacked_cab_path);
+        installer::patch::InstallationSet::UnpackCab(
+            $cab_filename,
+            $msi,
+            $unpacked_cab_path);
+    }
+    else
+    {
+        $installer::logger::Info->printf("cab has already been unpacked to\n");
+        $installer::logger::Info->printf("    %s\n", $unpacked_cab_path);
+    }
+
+    $installer::logger::Info->decrease_indentation();
+}
+
+
+
+
+installer::logger::SetupSimpleLogging("c:/tmp/log");
+
+my $arguments = ProcessCommandline();
+$arguments->{'package-format'} = 'msi';
+
+print "preparing release build\n";
+my ($variables, undef, undef)
+    = installer::ziplist::read_openoffice_lst_file(
+        $arguments->{'lst-file'},
+        $arguments->{'product-name'},
+        undef);
+if ( ! defined $arguments->{'source-version'})
+{
+    $arguments->{'source-version'} = $variables->{'PREVIOUS_VERSION'};
+}
+$installer::logger::Info->printf("    reading data from '%s'\n", $arguments->{'lst-file'});
+$installer::logger::Info->printf("    product name is '%s'\n", $arguments->{'product-name'});
+$installer::logger::Info->printf("    output path is '%s'\n", $arguments->{'output-path'});
+$installer::logger::Info->printf("    source version is '%s'\n", $arguments->{'source-version'});
+
+foreach my $language (@{$arguments->{'languages'}})
+{
+    ProcessLanguage(
+        $arguments->{'source-version'},
+        $language,
+        $arguments->{'package-format'},
+        $arguments->{'product-name'});
+}
commit a0e2aa57219a86c722bca890de349897cc479725
Author: Andre Fischer <af at apache.org>
Date:   Tue Nov 12 13:37:30 2013 +0000

    123531: Removed the old and incomplete support for updates (patches).

diff --git a/instsetoo_native/util/openoffice.lst b/instsetoo_native/util/openoffice.lst
index 82ac49b..3b0bb5d 100644
--- a/instsetoo_native/util/openoffice.lst
+++ b/instsetoo_native/util/openoffice.lst
@@ -27,9 +27,7 @@ Globals
             NATIVEPROGRESS false
             REGISTRYLAYERNAME Layers
             SERVICEPACK 1
-            UPDATE_DATABASE 1
             CREATE_MSP_INSTALLSET 0
-            UPDATE_DATABASE_LISTNAME finals_instsetoo.txt
             PACKAGEMAP package_names.txt,package_names_ext.txt
             WINDOWSPATCHLEVEL 8
             OOOVENDOR Apache Software Foundation
diff --git a/setup_native/source/packinfo/finals_instsetoo.txt b/setup_native/source/packinfo/finals_instsetoo.txt
deleted file mode 100644
index d37a921..0000000
--- a/setup_native/source/packinfo/finals_instsetoo.txt
+++ /dev/null
@@ -1,35 +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.
-#  
-# *************************************************************
-
-# Comment line
-# Syntax:
-# Column 1: Product
-# Column 2: pro or nonpro
-# Column 3: languages, comma separated list
-# Column 4: path to msi database in installation set
-# Separator between columns is one or more than one tabulator
-
-# Examples:
-# OpenOffice	pro		en-US		\\<server>\<path>\msi\OOO300_m6_native_packed-1_en-US.9352\openofficeorg30.msi
-# OpenOffice	pro		en-US,de,es	\\<server>\<path>\msi\OOO300_m6_native_packed-1_en-US_de_es.9352\openofficeorg30.msi
-# OpenOffice	pro		de			\\<server>\<path>\msi\OOO300_m6_native_packed-1_de.9352\openofficeorg30.msi
-# OpenOfficeLanguagePack	pro	es	\\<server>\<path>\msi\OOO300_m6_native_packed-1_es.9352\openofficeorg30.msi
-# URE			pro		en-US		\\<server>\<path>\msi\OOO300_m6_native_packed-1_en-US.9352\ure14.msi
diff --git a/solenv/bin/make_installer.pl b/solenv/bin/make_installer.pl
index 4b56528..0837e56 100644
--- a/solenv/bin/make_installer.pl
+++ b/solenv/bin/make_installer.pl
@@ -75,7 +75,6 @@ use installer::windows::inifile;
 use installer::windows::java;
 use installer::windows::media;
 use installer::windows::msiglobal;
-use installer::windows::msp;
 use installer::windows::patch;
 use installer::windows::property;
 use installer::windows::removefile;
@@ -83,7 +82,6 @@ use installer::windows::registry;
 use installer::windows::selfreg;
 use installer::windows::shortcut;
 use installer::windows::strip;
-use installer::windows::update;
 use installer::windows::upgrade;
 use installer::worker;
 use installer::xpdinstaller;
@@ -709,30 +707,11 @@ for ( my $n = 0; $n <= $#installer::globals::languageproducts; $n++ )
     my $uniquefilename = "";
     my $revuniquefilename = "";
     my $revshortfilename = "";
-    my $allupdatesequences = "";
-    my $allupdatecomponents = "";
-    my $allupdatefileorder = "";
     my $allupdatecomponentorder = "";
     my $shortdirname = "";
     my $componentid = "";
     my $componentidkeypath = "";
     my $alloldproperties = "";
-    my $allupdatelastsequences = "";
-    my $allupdatediskids = "";
-
-    if ( $installer::globals::iswindowsbuild )
-    {
-        if ( $allvariableshashref->{'UPDATE_DATABASE'} )
-        {
-            $installer::logger::Info->print( "... analyzing update database ...\n" );
-            $refdatabase = installer::windows::update::readdatabase($allvariableshashref, $languagestringref, $includepatharrayref);
-
-            if ( $installer::globals::updatedatabase )
-            {
-                ($uniquefilename, $revuniquefilename, $revshortfilename, $allupdatesequences, $allupdatecomponents, $allupdatefileorder, $allupdatecomponentorder, $shortdirname, $componentid, $componentidkeypath, $alloldproperties, $allupdatelastsequences, $allupdatediskids) = installer::windows::update::create_database_hashes($refdatabase);
-            }
-        }
-    }
 
     ##############################################
     # Setting global code variables for Windows
@@ -1940,9 +1919,8 @@ for ( my $n = 0; $n <= $#installer::globals::languageproducts; $n++ )
         # Collection all available directory trees
         installer::windows::directory::collectdirectorytrees($directoriesforepmarrayref);
 
-        $filesinproductlanguageresolvedarrayref = installer::windows::file::create_files_table($filesinproductlanguageresolvedarrayref, \@allfilecomponents, $newidtdir, $allvariableshashref, $uniquefilename, $allupdatesequences, $allupdatecomponents, $allupdatefileorder);
+        $filesinproductlanguageresolvedarrayref = installer::windows::file::create_files_table($filesinproductlanguageresolvedarrayref, \@allfilecomponents, $newidtdir, $allvariableshashref, $uniquefilename);
         if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "productfiles17c.log", $filesinproductlanguageresolvedarrayref); }
-        if ( $installer::globals::updatedatabase ) { installer::windows::file::check_file_sequences($allupdatefileorder, $allupdatecomponentorder); }
 
         installer::windows::directory::create_directory_table($directoriesforepmarrayref, $newidtdir, $allvariableshashref, $shortdirname, $loggingdir);
         if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "productfiles18.log", $filesinproductlanguageresolvedarrayref); }
@@ -1966,7 +1944,7 @@ for ( my $n = 0; $n <= $#installer::globals::languageproducts; $n++ )
 
         installer::windows::featurecomponent::create_featurecomponent_table($filesinproductlanguageresolvedarrayref, $registryitemsinproductlanguageresolvedarrayref, $newidtdir);
 
-        installer::windows::media::create_media_table($filesinproductlanguageresolvedarrayref, $newidtdir, $allvariableshashref, $allupdatelastsequences, $allupdatediskids);
+        installer::windows::media::create_media_table($filesinproductlanguageresolvedarrayref, $newidtdir, $allvariableshashref);
         if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "productfiles20.log", $filesinproductlanguageresolvedarrayref); }
 
         installer::windows::font::create_font_table($filesinproductlanguageresolvedarrayref, $newidtdir);
@@ -2255,20 +2233,6 @@ for ( my $n = 0; $n <= $#installer::globals::languageproducts; $n++ )
         installer::worker::clean_output_tree(); # removing directories created in the output tree
         ($is_success, $finalinstalldir) = installer::worker::analyze_and_save_logfile($loggingdir, $installdir, $installlogdir, $allsettingsarrayref, $languagestringref, $current_install_number);
 
-        #######################################################
-        # Creating Windows msp patches
-        #######################################################
-
-        if (( $is_success ) && ( $installer::globals::updatedatabase ) && ( $allvariableshashref->{'CREATE_MSP_INSTALLSET'} ))
-        {
-            # Required:
-            # Temp path for administrative installations: $installer::globals::temppath
-            # Path of new installation set: $finalinstalldir
-            # Path of old installation set: $installer::globals::updatedatabasepath
-            my $mspdir = installer::windows::msp::create_msp_patch($finalinstalldir, $includepatharrayref, $allvariableshashref, $languagestringref, $languagesarrayref, $filesinproductlanguageresolvedarrayref);
-            ($is_success, $finalinstalldir) = installer::worker::analyze_and_save_logfile($loggingdir, $mspdir, $installlogdir, $allsettingsarrayref, $languagestringref, $current_install_number);
-            installer::worker::clean_output_tree(); # removing directories created in the output tree
-        }
 
         #######################################################
         # Creating download installation set
diff --git a/solenv/bin/modules/installer/globals.pm b/solenv/bin/modules/installer/globals.pm
index d388b5f..e545da8 100644
--- a/solenv/bin/modules/installer/globals.pm
+++ b/solenv/bin/modules/installer/globals.pm
@@ -226,14 +226,8 @@ BEGIN
     @linkrpms = ();
     $archiveformat = "";
     $minorupgradekey = "";
-    $updatelastsequence = 0;
-    $updatesequencecounter = 0;
-    $updatedatabase = 0;
-    $updatedatabasepath = "";
     $pfffileexists = 0;
     $pffcabfilename = "ooobasis3.0_pff.cab";
-    %newupdatefiles = ();
-    %allusedupdatesequences = ();
     $mergefiles_added_into_collector = 0;
     $creating_windows_installer_patch = 0;
 
diff --git a/solenv/bin/modules/installer/windows/component.pm b/solenv/bin/modules/installer/windows/component.pm
index 2804cb5..f285197 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 86be8a2..5c9e5c7 100644
--- a/solenv/bin/modules/installer/windows/directory.pm
+++ b/solenv/bin/modules/installer/windows/directory.pm
@@ -358,8 +358,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 +370,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};
         }
diff --git a/solenv/bin/modules/installer/windows/file.pm b/solenv/bin/modules/installer/windows/file.pm
index b11f348..9e0169d 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,85 +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'}} ) ||

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list