[haiku-commits] haiku: hrev47473 - src/kits/package/hpkg src/bin/package headers/private/package/hpkg

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 8 Jul 2014 22:10:38 +0200 (CEST)

hrev47473 adds 4 changesets to branch 'master'
old head: d229332a33feb23d9ca9f3869ec7c4e4b09a990f
new head: a629567a9001547736cfe892cdf992be16868fed
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a629567+%5Ed229332

----------------------------------------------------------------------------

f5a20d5: package kit: PackageFileHeapReader::Init(): Sanity checks
  
  Make sure the compressed/uncompressed heap size and the chunk size
  table look plausible, so we can rely on the values later. Fixes
  potential crashes for corrupt packages.

2fc2aeb: PackageWriterImpl: Move _Finish() impl to match order in header

cdfeba5: BPackageWriter: Add Recompress()
  
  Allows rewriting an existing package file with a different compression.

a629567: package: Add command recompress
  
  The streaming feature for -0 is missing yet.

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

15 files changed, 380 insertions(+), 68 deletions(-)
headers/os/package/hpkg/PackageReader.h          |   4 +
headers/os/package/hpkg/PackageWriter.h          |   6 +
.../package/hpkg/PackageFileHeapAccessorBase.h   |   4 +
headers/private/package/hpkg/PackageReaderImpl.h |   5 +
headers/private/package/hpkg/PackageWriterImpl.h |   6 +
headers/private/package/hpkg/WriterImplBase.h    |   8 +
src/bin/package/Jamfile                          |   1 +
src/bin/package/command_recompress.cpp           | 128 ++++++++++++
src/bin/package/package.cpp                      |  16 ++
src/bin/package/package.h                        |   1 +
.../package/hpkg/PackageFileHeapAccessorBase.cpp |  10 +
src/kits/package/hpkg/PackageFileHeapReader.cpp  |  38 +++-
src/kits/package/hpkg/PackageWriter.cpp          |  12 ++
src/kits/package/hpkg/PackageWriterImpl.cpp      | 208 +++++++++++++------
src/tools/package/Jamfile                        |   1 +

############################################################################

Commit:      f5a20d5ff15b0153a8df4733ef28f5b3bc2b8489
URL:         http://cgit.haiku-os.org/haiku/commit/?id=f5a20d5
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Mon Jul  7 18:59:05 2014 UTC

package kit: PackageFileHeapReader::Init(): Sanity checks

Make sure the compressed/uncompressed heap size and the chunk size
table look plausible, so we can rely on the values later. Fixes
potential crashes for corrupt packages.

----------------------------------------------------------------------------

diff --git a/src/kits/package/hpkg/PackageFileHeapReader.cpp 
b/src/kits/package/hpkg/PackageFileHeapReader.cpp
index 6b19326..056ca4d 100644
--- a/src/kits/package/hpkg/PackageFileHeapReader.cpp
+++ b/src/kits/package/hpkg/PackageFileHeapReader.cpp
@@ -44,17 +44,32 @@ PackageFileHeapReader::~PackageFileHeapReader()
 status_t
 PackageFileHeapReader::Init()
 {
-       if (fUncompressedHeapSize == 0)
+       if (fUncompressedHeapSize == 0) {
+               if (fCompressedHeapSize != 0) {
+                       fErrorOutput->PrintError(
+                               "Invalid total compressed heap size (!= 0, 
empty heap)\n");
+                       return B_BAD_DATA;
+               }
                return B_OK;
+       }
 
        // Determine number of chunks and adjust the compressed heap size 
(subtract
        // the size of the chunk size array at the end). Note that the size of 
the
-       // last chunk has not been saved, since it size is implied.
+       // last chunk has not been saved, since its size is implied.
        ssize_t chunkCount = (fUncompressedHeapSize + kChunkSize - 1) / 
kChunkSize;
-       if (chunkCount <= 0)
+       if (chunkCount == 0)
                return B_OK;
 
-       fCompressedHeapSize -= (chunkCount - 1) * 2;
+       size_t chunkSizeTableSize = (chunkCount - 1) * 2; 
+       if (fCompressedHeapSize <= chunkSizeTableSize) {
+               fErrorOutput->PrintError(
+                       "Invalid total compressed heap size (%" B_PRIu64 ", "
+                       "uncompressed %" B_PRIu64 ")\n", fCompressedHeapSize,
+                       fUncompressedHeapSize);
+               return B_BAD_DATA;
+       }
+
+       fCompressedHeapSize -= chunkSizeTableSize;
 
        // allocate a buffer
        uint16* buffer = (uint16*)malloc(kChunkSize);
@@ -80,6 +95,21 @@ PackageFileHeapReader::Init()
                offset += toRead * 2;
        }
 
+       // Sanity check: The sum of the chunk sizes must match the compressed 
heap
+       // size. The information aren't stored redundantly, so we check, if 
things
+       // look at least plausible.
+       uint64 lastChunkOffset = fOffsets[chunkCount - 1];
+       if (lastChunkOffset >= fCompressedHeapSize
+                       || fCompressedHeapSize - lastChunkOffset > kChunkSize
+                       || fCompressedHeapSize - lastChunkOffset
+                               > fUncompressedHeapSize - (chunkCount - 1) * 
kChunkSize) {
+               fErrorOutput->PrintError(
+                       "Invalid total compressed heap size (%" B_PRIu64 ", 
uncompressed: "
+                       "%" B_PRIu64 ", last chunk offset: %" B_PRIu64 ")\n",
+                       fCompressedHeapSize, fUncompressedHeapSize, 
lastChunkOffset);
+               return B_BAD_DATA;
+       }
+
        return B_OK;
 }
 

############################################################################

Commit:      2fc2aebcba504f169142344ff04ae75fbb0e7ccb
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2fc2aeb
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Mon Jul  7 19:31:25 2014 UTC

PackageWriterImpl: Move _Finish() impl to match order in header

----------------------------------------------------------------------------

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp 
b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 8f5cadd..ed717dd 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -662,6 +662,69 @@ PackageWriterImpl::_Init(const char* fileName,
 
 
 status_t
+PackageWriterImpl::_Finish()
+{
+       // write entries
+       for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
+                       Entry* entry = it.Next();) {
+               char pathBuffer[B_PATH_NAME_LENGTH];
+               pathBuffer[0] = '\0';
+               _AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
+       }
+
+       hpkg_header header;
+
+       // write the TOC and package attributes
+       uint64 tocLength;
+       _WriteTOC(header, tocLength);
+
+       uint64 attributesLength;
+       _WritePackageAttributes(header, attributesLength);
+
+       // flush the heap
+       status_t error = fHeapWriter->Finish();
+       if (error != B_OK)
+               return error;
+
+       uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize();
+
+       header.heap_compression = 
B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB);
+       header.heap_chunk_size = 
B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize());
+       header.heap_size_compressed = 
B_HOST_TO_BENDIAN_INT64(compressedHeapSize);
+       header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64(
+               fHeapWriter->UncompressedHeapSize());
+
+       // Truncate the file to the size it is supposed to have. In update 
mode, it
+       // can be greater when one or more files are shrunk. In creation mode it
+       // should already have the correct size.
+       off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize;
+       if (ftruncate(FD(), totalSize) != 0) {
+               fListener->PrintError("Failed to truncate package file to new "
+                       "size: %s\n", strerror(errno));
+               return errno;
+       }
+
+       fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength,
+               attributesLength, totalSize);
+
+       // prepare the header
+
+       // general
+       header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
+       header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize);
+       header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
+       header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
+       header.minor_version = B_HOST_TO_BENDIAN_INT16(B_HPKG_MINOR_VERSION);
+
+       // write the header
+       RawWriteBuffer(&header, sizeof(hpkg_header), 0);
+
+       SetFinished(true);
+       return B_OK;
+}
+
+
+status_t
 PackageWriterImpl::_CheckLicenses()
 {
        BPath systemLicensePath;
@@ -1071,70 +1134,6 @@ PackageWriterImpl::_AttributeRemoved(Attribute* 
attribute)
 
 
 status_t
-PackageWriterImpl::_Finish()
-{
-       // write entries
-       for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
-                       Entry* entry = it.Next();) {
-               char pathBuffer[B_PATH_NAME_LENGTH];
-               pathBuffer[0] = '\0';
-               _AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
-       }
-
-       hpkg_header header;
-
-       // write the TOC and package attributes
-       uint64 tocLength;
-       _WriteTOC(header, tocLength);
-
-       uint64 attributesLength;
-       _WritePackageAttributes(header, attributesLength);
-
-       // flush the heap
-       status_t error = fHeapWriter->Finish();
-       if (error != B_OK)
-               return error;
-
-       uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize();
-
-       header.heap_compression = 
B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB);
-       header.heap_chunk_size = 
B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize());
-       header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(
-               fHeapWriter->CompressedHeapSize());
-       header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64(
-               fHeapWriter->UncompressedHeapSize());
-
-       // Truncate the file to the size it is supposed to have. In update 
mode, it
-       // can be greater when one or more files are shrunk. In creation mode it
-       // should already have the correct size.
-       off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize;
-       if (ftruncate(FD(), totalSize) != 0) {
-               fListener->PrintError("Failed to truncate package file to new "
-                       "size: %s\n", strerror(errno));
-               return errno;
-       }
-
-       fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength,
-               attributesLength, totalSize);
-
-       // prepare the header
-
-       // general
-       header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
-       header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize);
-       header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
-       header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
-       header.minor_version = B_HOST_TO_BENDIAN_INT16(B_HPKG_MINOR_VERSION);
-
-       // write the header
-       RawWriteBuffer(&header, sizeof(hpkg_header), 0);
-
-       SetFinished(true);
-       return B_OK;
-}
-
-
-status_t
 PackageWriterImpl::_RegisterEntry(const char* fileName, int fd)
 {
        if (*fileName == '\0') {

############################################################################

Commit:      cdfeba5a1e49d0993e7ab6853c77392bbc10d3c4
URL:         http://cgit.haiku-os.org/haiku/commit/?id=cdfeba5
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Tue Jul  8 19:58:10 2014 UTC

BPackageWriter: Add Recompress()

Allows rewriting an existing package file with a different compression.

----------------------------------------------------------------------------

diff --git a/headers/os/package/hpkg/PackageReader.h 
b/headers/os/package/hpkg/PackageReader.h
index e5b8369..7ab4976 100644
--- a/headers/os/package/hpkg/PackageReader.h
+++ b/headers/os/package/hpkg/PackageReader.h
@@ -24,6 +24,7 @@ class BAbstractBufferedDataReader;
 class BErrorOutput;
 class BLowLevelPackageContentHandler;
 class BPackageContentHandler;
+class BPackageWriter;
 
 
 class BPackageReader {
@@ -44,6 +45,9 @@ public:
                                                                        // Only 
valid as long as the reader lives.
 
 private:
+                       friend class BPackageWriter;
+
+private:
                        PackageReaderImpl*      fImpl;
 };
 
diff --git a/headers/os/package/hpkg/PackageWriter.h 
b/headers/os/package/hpkg/PackageWriter.h
index 99c924b..996f83f 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -16,6 +16,9 @@ namespace BPackageKit {
 namespace BHPKG {
 
 
+class BPackageReader;
+
+
 namespace BPrivate {
        class PackageWriterImpl;
 }
@@ -72,6 +75,9 @@ public:
                        status_t                        AddEntry(const char* 
fileName, int fd = -1);
                        status_t                        Finish();
 
+                       status_t                        
Recompress(BPackageReader* reader);
+                                                                       // to 
be called after Init(); no Finish()
+
 private:
                        PackageWriterImpl*      fImpl;
 };
diff --git a/headers/private/package/hpkg/PackageFileHeapAccessorBase.h 
b/headers/private/package/hpkg/PackageFileHeapAccessorBase.h
index 2d9eed3..b5463dd 100644
--- a/headers/private/package/hpkg/PackageFileHeapAccessorBase.h
+++ b/headers/private/package/hpkg/PackageFileHeapAccessorBase.h
@@ -92,6 +92,10 @@ public:
                        void                            SetFD(int fd)
                                                                        { fFD = 
fd; }
 
+                       uint64                          HeapOverhead(uint64 
uncompressedSize) const;
+                                                                       // 
additional bytes needed when storing
+                                                                       // the 
given amount of data
+
        // BAbstractBufferedDataReader
        virtual status_t                        ReadDataToOutput(off_t offset,
                                                                        size_t 
size, BDataIO* output);
diff --git a/headers/private/package/hpkg/PackageReaderImpl.h 
b/headers/private/package/hpkg/PackageReaderImpl.h
index aaac66c..3f7522b 100644
--- a/headers/private/package/hpkg/PackageReaderImpl.h
+++ b/headers/private/package/hpkg/PackageReaderImpl.h
@@ -22,6 +22,9 @@ class BPackageEntryAttribute;
 namespace BPrivate {
 
 
+class PackageWriterImpl;
+
+
 class PackageReaderImpl : public ReaderImplBase {
        typedef ReaderImplBase          inherited;
 public:
@@ -58,6 +61,8 @@ private:
                        struct EntryAttributeHandler;
                        struct RootAttributeHandler;
 
+                       friend class PackageWriterImpl;
+
 private:
                        status_t                        
_ParseTOC(AttributeHandlerContext* context,
                                                                        
AttributeHandler* rootAttributeHandler);
diff --git a/headers/private/package/hpkg/PackageWriterImpl.h 
b/headers/private/package/hpkg/PackageWriterImpl.h
index f74c1ba..1202783 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -35,6 +35,7 @@ class BPackageWriterParameters;
 namespace BPrivate {
 
 
+class PackageReaderImpl;
 struct hpkg_header;
 
 
@@ -53,6 +54,9 @@ public:
                        status_t                        AddEntry(const char* 
fileName, int fd = -1);
                        status_t                        Finish();
 
+                       status_t                        
Recompress(PackageReaderImpl* reader);
+                                                                       // to 
be called after Init(); no Finish()
+
 private:
                        struct Attribute;
                        struct PackageContentHandler;
@@ -67,6 +71,8 @@ private:
                                                                        const 
BPackageWriterParameters& parameters);
                        status_t                        _Finish();
 
+                       status_t                        
_Recompress(PackageReaderImpl* reader);
+
                        status_t                        _RegisterEntry(const 
char* fileName, int fd);
                        Entry*                          _RegisterEntry(Entry* 
parent,
                                                                        const 
char* name, size_t nameLength, int fd,
diff --git a/headers/private/package/hpkg/WriterImplBase.h 
b/headers/private/package/hpkg/WriterImplBase.h
index 99afd30..38496c4 100644
--- a/headers/private/package/hpkg/WriterImplBase.h
+++ b/headers/private/package/hpkg/WriterImplBase.h
@@ -151,6 +151,7 @@ protected:
 
        inline  int                                     FD() const;
        inline  uint32                          Flags() const;
+       inline  const BPackageWriterParameters& Parameters() const;
 
        inline  const PackageAttributeList&     PackageAttributes() const;
        inline  PackageAttributeList&   PackageAttributes();
@@ -230,6 +231,13 @@ WriterImplBase::Flags() const
 }
 
 
+inline const BPackageWriterParameters&
+WriterImplBase::Parameters() const
+{
+       return fParameters;
+}
+
+
 inline const WriterImplBase::PackageAttributeList&
 WriterImplBase::PackageAttributes() const
 {
diff --git a/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp 
b/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp
index ebc2d10..b8981e1 100644
--- a/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp
+++ b/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp
@@ -144,6 +144,16 @@ PackageFileHeapAccessorBase::~PackageFileHeapAccessorBase()
 }
 
 
+uint64
+PackageFileHeapAccessorBase::HeapOverhead(uint64 uncompressedSize) const
+{
+       // Determine number of chunks and the size of the chunk size table. Note
+       // that the size of the last chunk is not saved, since its size is 
implied.
+       size_t chunkCount = (uncompressedSize + kChunkSize - 1) / kChunkSize;
+       return chunkCount > 1 ? (chunkCount - 1) * 2 : 0;
+}
+
+
 status_t
 PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size,
        BDataIO* output)
diff --git a/src/kits/package/hpkg/PackageWriter.cpp 
b/src/kits/package/hpkg/PackageWriter.cpp
index 2a5582e..15b877f 100644
--- a/src/kits/package/hpkg/PackageWriter.cpp
+++ b/src/kits/package/hpkg/PackageWriter.cpp
@@ -8,6 +8,8 @@
 
 #include <new>
 
+#include <package/hpkg/PackageReader.h>
+
 #include <package/hpkg/PackageWriterImpl.h>
 
 
@@ -128,6 +130,16 @@ BPackageWriter::Finish()
 }
 
 
+status_t
+BPackageWriter::Recompress(BPackageReader* reader)
+{
+       if (fImpl == NULL)
+               return B_NO_INIT;
+
+       return fImpl->Recompress(reader->fImpl);
+}
+
+
 }      // namespace BHPKG
 
 }      // namespace BPackageKit
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp 
b/src/kits/package/hpkg/PackageWriterImpl.cpp
index ed717dd..740f454 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -38,6 +38,7 @@
 #include <package/hpkg/HPKGDefsPrivate.h>
 
 #include <package/hpkg/DataReader.h>
+#include <package/hpkg/PackageFileHeapReader.h>
 #include <package/hpkg/PackageFileHeapWriter.h>
 #include <package/hpkg/PackageReaderImpl.h>
 #include <package/hpkg/Stacker.h>
@@ -606,6 +607,23 @@ PackageWriterImpl::Finish()
 
 
 status_t
+PackageWriterImpl::Recompress(PackageReaderImpl* reader)
+{
+       if (reader == NULL)
+               return B_BAD_VALUE;
+
+       try {
+               return _Recompress(reader);
+       } catch (status_t error) {
+               return error;
+       } catch (std::bad_alloc) {
+               fListener->PrintError("Out of memory!\n");
+               return B_NO_MEMORY;
+       }
+}
+
+
+status_t
 PackageWriterImpl::_Init(const char* fileName,
        const BPackageWriterParameters& parameters)
 {
@@ -725,6 +743,69 @@ PackageWriterImpl::_Finish()
 
 
 status_t
+PackageWriterImpl::_Recompress(PackageReaderImpl* reader)
+{
+       if (reader == NULL)
+               return B_BAD_VALUE;
+
+       // read the header
+       hpkg_header header;
+       status_t error = reader->ReadBuffer(0, &header, sizeof(header));
+       if (error != B_OK) {
+               fListener->PrintError("Failed to reader hpkg header: %s\n",
+                       strerror(error));
+               return error;
+       }
+
+       // Update some header fields, assuming no compression. We'll rewrite the
+       // header later, should compression have been used. Doing it this way 
allows
+       // for streaming an uncompressed package.
+       uint64 uncompressedHeapSize
+               = reader->RawHeapReader()->UncompressedHeapSize();
+       uint64 compressedHeapSize = uncompressedHeapSize
+               + fHeapWriter->HeapOverhead(uncompressedHeapSize);
+
+       off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize;
+
+       header.heap_compression = 
B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB);
+       header.heap_chunk_size = 
B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize());
+       header.heap_size_compressed = 
B_HOST_TO_BENDIAN_INT64(compressedHeapSize);
+       header.heap_size_uncompressed
+               = B_HOST_TO_BENDIAN_INT64(uncompressedHeapSize);
+       header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
+
+       if (Parameters().CompressionLevel() == 0)
+               RawWriteBuffer(&header, sizeof(hpkg_header), 0);
+
+       // copy the heap data
+       uint64 bytesCompressed;
+       error = fHeapWriter->AddData(*reader->RawHeapReader(), 
uncompressedHeapSize,
+               bytesCompressed);
+       if (error != B_OK)
+               return error;
+
+       // flush the heap
+       error = fHeapWriter->Finish();
+       if (error != B_OK)
+               return error;
+
+       // If compression is enabled, update and write the header.
+       if (Parameters().CompressionLevel() != 0) {
+               compressedHeapSize = fHeapWriter->CompressedHeapSize();
+               totalSize = fHeapWriter->HeapOffset() + 
(off_t)compressedHeapSize;
+               header.heap_size_compressed = 
B_HOST_TO_BENDIAN_INT64(compressedHeapSize);
+               header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
+
+               // write the header
+               RawWriteBuffer(&header, sizeof(hpkg_header), 0);
+       }
+
+       SetFinished(true);
+       return B_OK;
+}
+
+
+status_t
 PackageWriterImpl::_CheckLicenses()
 {
        BPath systemLicensePath;

############################################################################

Revision:    hrev47473
Commit:      a629567a9001547736cfe892cdf992be16868fed
URL:         http://cgit.haiku-os.org/haiku/commit/?id=a629567
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Tue Jul  8 19:59:44 2014 UTC

package: Add command recompress

The streaming feature for -0 is missing yet.

----------------------------------------------------------------------------

diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile
index 80f0c95..111b2de 100644
--- a/src/bin/package/Jamfile
+++ b/src/bin/package/Jamfile
@@ -9,6 +9,7 @@ BinCommand package :
        command_extract.cpp
        command_info.cpp
        command_list.cpp
+       command_recompress.cpp
        package.cpp
        PackageWriterListener.cpp
        PackageWritingUtils.cpp
diff --git a/src/bin/package/command_recompress.cpp 
b/src/bin/package/command_recompress.cpp
new file mode 100644
index 0000000..b1cd6d0
--- /dev/null
+++ b/src/bin/package/command_recompress.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <package/hpkg/HPKGDefs.h>
+#include <package/hpkg/PackageReader.h>
+#include <package/hpkg/PackageWriter.h>
+
+#include "package.h"
+#include "PackageWriterListener.h"
+
+
+using BPackageKit::BHPKG::BPackageReader;
+using BPackageKit::BHPKG::BPackageWriter;
+using BPackageKit::BHPKG::BPackageWriterListener;
+using BPackageKit::BHPKG::BPackageWriterParameters;
+
+
+int
+command_recompress(int argc, const char* const* argv)
+{
+       bool quiet = false;
+       bool verbose = false;
+       int32 compressionLevel = 
BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST;
+
+       while (true) {
+               static struct option sLongOptions[] = {
+                       { "help", no_argument, 0, 'h' },
+                       { "quiet", no_argument, 0, 'q' },
+                       { "verbose", no_argument, 0, 'v' },
+                       { 0, 0, 0, 0 }
+               };
+
+               opterr = 0; // don't print errors
+               int c = getopt_long(argc, (char**)argv, "+0123456789:hqv",
+                       sLongOptions, NULL);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               compressionLevel = c - '0';
+                               break;
+
+                       case 'h':
+                               print_usage_and_exit(false);
+                               break;
+
+                       case 'q':
+                               quiet = true;
+                               break;
+
+                       case 'v':
+                               verbose = true;
+                               break;
+
+                       default:
+                               print_usage_and_exit(true);
+                               break;
+               }
+       }
+
+       // The remaining arguments are the input package file and optionally the
+       // output package file, i.e. one or two more arguments.
+       if (argc - optind < 1 || argc - optind > 2)
+               print_usage_and_exit(true);
+
+       const char* inputPackageFileName = argv[optind++];
+       const char* outputPackageFileName = optind < argc ? argv[optind++] : 
NULL;
+
+       // If compression is used, an output file is required.
+       if (compressionLevel != 0 && outputPackageFileName == NULL) {
+               fprintf(stderr, "Error: Writing to stdout is supported only 
with "
+                       "compression level 0.\n");
+               return 1;
+       }
+
+       // TODO: Implement streaming support!
+       if (outputPackageFileName == NULL) {
+               fprintf(stderr, "Error: Writing to stdout is not supported 
yet.\n");
+               return 1;
+       }
+
+       // open the input package
+       PackageWriterListener listener(verbose, quiet);
+
+       BPackageReader packageReader(&listener);
+       status_t error = packageReader.Init(inputPackageFileName);
+       if (error != B_OK)
+               return 1;
+
+       // write the output package
+       BPackageWriterParameters writerParameters;
+       writerParameters.SetCompressionLevel(compressionLevel);
+
+       BPackageWriter packageWriter(&listener);
+       error = packageWriter.Init(outputPackageFileName, &writerParameters);
+       if (error != B_OK)
+               return 1;
+
+       error = packageWriter.Recompress(&packageReader);
+       if (error != B_OK)
+               return 1;
+
+       if (verbose)
+               printf("\nsuccessfully wrote package '%s'\n", 
outputPackageFileName);
+
+       return 0;
+}
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index 627755f..6bcab5c 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -96,6 +96,19 @@ static const char* kUsage =
        "    -i         - Only print the meta information, not the files.\n"
        "    -p         - Only print a list of file paths.\n"
        "\n"
+       "  recompress [ <options> ] <input package> [ <output package> ]\n"
+       "    Reads the package file <input package> and writes it to new 
package\n"
+       "    <output package> using the specified compression options. If the\n"
+       "    compression level 0 is specified (i.e. no compression), "
+               "<output package>\n"
+       "    can be omitted, in which case the data are written to stdout.\n"
+       "\n"
+       "    -0 ... -9  - Use compression level 0 ... 9. 0 means no, 9 best "
+               "compression.\n"
+       "                 Defaults to 9.\n"
+       "    -q         - Be quiet (don't show any output except for errors).\n"
+       "    -v         - Be verbose (show more info about created package).\n"
+       "\n"
        "Common Options:\n"
        "  -h, --help   - Print this usage info.\n"
 ;
@@ -134,6 +147,9 @@ main(int argc, const char* const* argv)
        if (strcmp(command, "info") == 0)
                return command_info(argc - 1, argv + 1);
 
+       if (strcmp(command, "recompress") == 0)
+               return command_recompress(argc - 1, argv + 1);
+
        if (strcmp(command, "help") == 0)
                print_usage_and_exit(false);
        else
diff --git a/src/bin/package/package.h b/src/bin/package/package.h
index 966386b..f15268b 100644
--- a/src/bin/package/package.h
+++ b/src/bin/package/package.h
@@ -14,6 +14,7 @@ int           command_dump(int argc, const char* const* argv);
 int            command_extract(int argc, const char* const* argv);
 int            command_info(int argc, const char* const* argv);
 int            command_list(int argc, const char* const* argv);
+int            command_recompress(int argc, const char* const* argv);
 
 
 #endif // PACKAGE_H
diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index b9dfd36..891bf6d 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -13,6 +13,7 @@ BuildPlatformMain <build>package :
        command_extract.cpp
        command_info.cpp
        command_list.cpp
+       command_recompress.cpp
        package.cpp
        PackageWriterListener.cpp
        PackageWritingUtils.cpp


Other related posts:

  • » [haiku-commits] haiku: hrev47473 - src/kits/package/hpkg src/bin/package headers/private/package/hpkg - ingo_weinhold