diff --git a/headers/os/package/hpkg/PackageReader.h b/headers/os/package/hpkg/PackageReader.h index e5b8369385..7ab4976ff5 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 { @@ -43,6 +44,9 @@ public: BAbstractBufferedDataReader* HeapReader() const; // 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 99c924bfec..996f83f418 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 2d9eed3510..b5463dda9e 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 aaac66c0a3..3f7522baa6 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 f74c1ba3f1..1202783c24 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 99afd30c00..38496c4e54 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 ebc2d10967..b8981e1205 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 2a5582e378..15b877fcc2 100644 --- a/src/kits/package/hpkg/PackageWriter.cpp +++ b/src/kits/package/hpkg/PackageWriter.cpp @@ -8,6 +8,8 @@ #include +#include + #include @@ -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 ed717dd212..740f454944 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -605,6 +606,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) @@ -724,6 +742,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() {