Added support for data compression via zlib. Compression support for the TOC
and package attributes sections is still missing, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34043 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
fbe3b5b994
commit
aece77090d
@ -1,11 +1,14 @@
|
||||
SubDir HAIKU_TOP src bin package ;
|
||||
|
||||
UseLibraryHeaders zlib ;
|
||||
UsePrivateHeaders kernel shared ;
|
||||
UsePrivateHeaders haiku_package ;
|
||||
|
||||
DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ;
|
||||
# TODO: Remove when it is complete!
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) compression ] ;
|
||||
|
||||
BinCommand package :
|
||||
command_create.cpp
|
||||
command_dump.cpp
|
||||
@ -20,6 +23,12 @@ BinCommand package :
|
||||
PackageReader.cpp
|
||||
PackageWriter.cpp
|
||||
Strings.cpp
|
||||
|
||||
# compression
|
||||
ZlibCompressionBase.cpp
|
||||
ZlibCompressor.cpp
|
||||
ZlibDecompressor.cpp
|
||||
:
|
||||
z
|
||||
$(TARGET_LIBSUPC++)
|
||||
;
|
||||
|
@ -13,6 +13,7 @@ PackageData::PackageData()
|
||||
:
|
||||
fCompressedSize(0),
|
||||
fUncompressedSize(0),
|
||||
fChunkSize(0),
|
||||
fCompression(B_HPKG_COMPRESSION_NONE),
|
||||
fEncodedInline(true)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
{ return fUncompressedSize; }
|
||||
uint64 Offset() const { return fOffset; }
|
||||
uint32 Compression() const { return fCompression; }
|
||||
uint32 ChunkSize() const { return fChunkSize; }
|
||||
|
||||
bool IsEncodedInline() const
|
||||
{ return fEncodedInline; }
|
||||
@ -31,6 +32,8 @@ public:
|
||||
{ fCompression = compression; }
|
||||
void SetUncompressedSize(uint64 size)
|
||||
{ fUncompressedSize = size; }
|
||||
void SetChunkSize(uint32 size)
|
||||
{ fChunkSize = size; }
|
||||
|
||||
private:
|
||||
uint64 fCompressedSize;
|
||||
@ -39,6 +42,7 @@ private:
|
||||
uint64 fOffset;
|
||||
uint8 fInlineData[B_HPKG_MAX_INLINE_DATA_SIZE];
|
||||
};
|
||||
uint32 fChunkSize;
|
||||
uint32 fCompression;
|
||||
bool fEncodedInline;
|
||||
};
|
||||
|
@ -6,11 +6,23 @@
|
||||
|
||||
#include "PackageDataReader.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include <haiku_package.h>
|
||||
|
||||
#include "PackageData.h"
|
||||
#include "ZlibDecompressor.h"
|
||||
|
||||
|
||||
// minimum/maximum zlib chunk size we consider sane
|
||||
static const size_t kMinSaneZlibChunkSize = 1024;
|
||||
static const size_t kMaxSaneZlibChunkSize = 10 * 1024 * 1024;
|
||||
|
||||
// maximum number of entries in the zlib offset table buffer
|
||||
static const uint32 kMaxZlibOffsetTableBufferSize = 512;
|
||||
|
||||
|
||||
// #pragma mark - PackageDataReader
|
||||
@ -66,7 +78,7 @@ public:
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if ((uint64)offset > fSize || size > fSize - offset)
|
||||
return B_ERROR;
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return fDataReader->ReadData(fOffset + offset, buffer, size);
|
||||
}
|
||||
@ -77,6 +89,252 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - ZlibPackageDataReader
|
||||
|
||||
|
||||
class ZlibPackageDataReader : public PackageDataReader {
|
||||
public:
|
||||
ZlibPackageDataReader(DataReader* dataReader)
|
||||
:
|
||||
PackageDataReader(dataReader),
|
||||
fOffsetTable(NULL),
|
||||
fReadBuffer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~ZlibPackageDataReader()
|
||||
{
|
||||
delete[] fOffsetTable;
|
||||
free(fReadBuffer);
|
||||
}
|
||||
|
||||
status_t Init(const PackageData& data)
|
||||
{
|
||||
fOffset = data.Offset();
|
||||
fCompressedSize = data.CompressedSize();
|
||||
fUncompressedSize = data.UncompressedSize();
|
||||
fChunkSize = data.ChunkSize();
|
||||
|
||||
// validate chunk size
|
||||
if (fChunkSize == 0)
|
||||
fChunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
|
||||
if (fChunkSize < kMinSaneZlibChunkSize
|
||||
|| fChunkSize > kMaxSaneZlibChunkSize) {
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
fChunkCount = (fUncompressedSize + (fChunkSize - 1)) / fChunkSize;
|
||||
fOffsetTableSize = (fChunkCount - 1) * sizeof(uint64);
|
||||
if (fOffsetTableSize >= fCompressedSize)
|
||||
return B_BAD_DATA;
|
||||
|
||||
// allocate a buffer for the offset table
|
||||
if (fChunkCount > 1) {
|
||||
fOffsetTableBufferEntryCount = std::min(fChunkCount - 1,
|
||||
(uint64)kMaxZlibOffsetTableBufferSize);
|
||||
fOffsetTable = new(std::nothrow) uint64[
|
||||
fOffsetTableBufferEntryCount];
|
||||
if (fOffsetTable == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fOffsetTableIndex = -1;
|
||||
// mark the table content invalid
|
||||
} else
|
||||
fChunkSize = fUncompressedSize;
|
||||
|
||||
// allocate the read/uncompress buffer
|
||||
fReadBuffer = (uint8*)malloc(fChunkSize * 2);
|
||||
if (fReadBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fUncompressBuffer = fReadBuffer + fChunkSize;
|
||||
fUncompressedChunk = -1;
|
||||
// mark content invalid
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
virtual uint64 Size() const
|
||||
{
|
||||
return fUncompressedSize;
|
||||
}
|
||||
|
||||
virtual size_t BlockSize() const
|
||||
{
|
||||
return fChunkSize;
|
||||
}
|
||||
|
||||
virtual status_t ReadData(off_t offset, void* _buffer, size_t size)
|
||||
{
|
||||
uint8* buffer = (uint8*)_buffer;
|
||||
|
||||
// check offset and size
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
if (offset < 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if ((uint64)offset > fUncompressedSize
|
||||
|| size > fUncompressedSize - offset) {
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// uncompress
|
||||
int64 chunkIndex = offset / fChunkSize;
|
||||
off_t chunkOffset = chunkIndex * fChunkSize;
|
||||
size_t inChunkOffset = offset - chunkOffset;
|
||||
|
||||
while (size > 0) {
|
||||
// read and uncompress the chunk
|
||||
status_t error = _ReadChunk(chunkIndex);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// copy data to buffer
|
||||
size_t toCopy = std::min(size, (size_t)fChunkSize - inChunkOffset);
|
||||
memcpy(buffer, fUncompressBuffer, toCopy);
|
||||
|
||||
buffer += toCopy;
|
||||
size -= toCopy;
|
||||
|
||||
chunkIndex++;
|
||||
chunkOffset += fChunkSize;
|
||||
inChunkOffset = 0;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
status_t _ReadChunk(int64 chunkIndex)
|
||||
{
|
||||
if (chunkIndex == fUncompressedChunk)
|
||||
return B_OK;
|
||||
|
||||
// get the chunk offset and size
|
||||
uint64 offset;
|
||||
uint32 compressedSize;
|
||||
status_t error = _GetCompressedChunkOffsetAndSize(chunkIndex, offset,
|
||||
compressedSize);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
uint32 uncompressedSize = (uint64)chunkIndex + 1 < fChunkCount
|
||||
? fChunkSize : fUncompressedSize - chunkIndex * fChunkSize;
|
||||
|
||||
// read the chunk
|
||||
if (compressedSize == uncompressedSize) {
|
||||
// the chunk is not compressed -- read it directly into the
|
||||
// uncompressed buffer
|
||||
error = fDataReader->ReadData(offset, fUncompressBuffer,
|
||||
compressedSize);
|
||||
} else {
|
||||
// read to the read buffer and uncompress
|
||||
error = fDataReader->ReadData(offset, fReadBuffer, compressedSize);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
size_t actuallyUncompressedSize;
|
||||
error = ZlibDecompressor().Decompress(fReadBuffer, compressedSize,
|
||||
fUncompressBuffer, uncompressedSize, actuallyUncompressedSize);
|
||||
if (error == B_OK && actuallyUncompressedSize != uncompressedSize)
|
||||
error = B_BAD_DATA;
|
||||
}
|
||||
|
||||
if (error != B_OK) {
|
||||
// error reading/decompressing data -- mark the cached data invalid
|
||||
fUncompressedChunk = -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
fUncompressedChunk = chunkIndex;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t _GetCompressedChunkOffsetAndSize(int64 chunkIndex, uint64& _offset,
|
||||
uint32& _size)
|
||||
{
|
||||
// get the offset
|
||||
uint64 offset;
|
||||
if (chunkIndex == 0) {
|
||||
// first chunk is at 0
|
||||
offset = 0;
|
||||
} else {
|
||||
status_t error = _GetCompressedChunkRelativeOffset(chunkIndex,
|
||||
offset);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
// get the end offset
|
||||
uint64 endOffset;
|
||||
if ((uint64)chunkIndex + 1 == fChunkCount) {
|
||||
// last chunk end with the end of the data
|
||||
endOffset = fCompressedSize - fOffsetTableSize;
|
||||
} else {
|
||||
status_t error = _GetCompressedChunkRelativeOffset(chunkIndex + 1,
|
||||
endOffset);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (endOffset < offset)
|
||||
return B_BAD_DATA;
|
||||
|
||||
_offset = fOffset + fOffsetTableSize + offset;
|
||||
_size = endOffset - offset;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t _GetCompressedChunkRelativeOffset(int64 chunkIndex,
|
||||
uint64& _offset)
|
||||
{
|
||||
if (fOffsetTableIndex < 0 || fOffsetTableIndex > chunkIndex
|
||||
|| fOffsetTableIndex + fOffsetTableBufferEntryCount <= chunkIndex) {
|
||||
// read the table at the given index, or, if we can, the whole table
|
||||
int64 readAtIndex = fChunkCount - 1 > fOffsetTableBufferEntryCount
|
||||
? chunkIndex : 1;
|
||||
uint32 entriesToRead = std::min(
|
||||
(uint64)fOffsetTableBufferEntryCount,
|
||||
fChunkCount - readAtIndex);
|
||||
|
||||
status_t error = fDataReader->ReadData(
|
||||
fOffset + (readAtIndex - 1) * sizeof(uint64),
|
||||
fOffsetTable, entriesToRead * sizeof(uint64));
|
||||
if (error != B_OK) {
|
||||
fOffsetTableIndex = -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
fOffsetTableIndex = readAtIndex;
|
||||
}
|
||||
|
||||
// get and check the offset
|
||||
_offset = fOffsetTable[chunkIndex - fOffsetTableIndex];
|
||||
if (_offset > fCompressedSize - fOffsetTableSize)
|
||||
return B_BAD_DATA;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 fOffset;
|
||||
uint64 fUncompressedSize;
|
||||
uint64 fCompressedSize;
|
||||
uint64 fOffsetTableSize;
|
||||
uint64 fChunkCount;
|
||||
uint32 fChunkSize;
|
||||
uint32 fOffsetTableBufferEntryCount;
|
||||
uint64* fOffsetTable;
|
||||
int32 fOffsetTableIndex;
|
||||
uint8* fReadBuffer;
|
||||
uint8* fUncompressBuffer;
|
||||
int64 fUncompressedChunk;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - PackageDataReaderFactory
|
||||
|
||||
|
||||
@ -92,8 +350,8 @@ PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader,
|
||||
dataReader);
|
||||
break;
|
||||
case B_HPKG_COMPRESSION_ZLIB:
|
||||
// TODO:...
|
||||
return B_UNSUPPORTED;;
|
||||
reader = new(std::nothrow) ZlibPackageDataReader(dataReader);
|
||||
break;
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ enum {
|
||||
ATTRIBUTE_INDEX_DATA,
|
||||
ATTRIBUTE_INDEX_DATA_SIZE,
|
||||
ATTRIBUTE_INDEX_DATA_COMPRESSION,
|
||||
ATTRIBUTE_INDEX_DATA_CHUNK_SIZE,
|
||||
ATTRIBUTE_INDEX_SYMLINK_PATH
|
||||
};
|
||||
|
||||
@ -78,6 +79,7 @@ static const standard_attribute_index_entry kStandardAttributeIndices[] = {
|
||||
MAKE_ATTRIBUTE_INDEX_ENTRY(DATA, RAW),
|
||||
MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_SIZE, UINT),
|
||||
MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_COMPRESSION, UINT),
|
||||
MAKE_ATTRIBUTE_INDEX_ENTRY(DATA_CHUNK_SIZE, UINT),
|
||||
MAKE_ATTRIBUTE_INDEX_ENTRY(SYMLINK_PATH, STRING),
|
||||
{}
|
||||
};
|
||||
@ -250,6 +252,10 @@ struct PackageReader::DataAttributeHandler : AttributeHandler {
|
||||
fData->SetCompression(value.unsignedInt);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
case ATTRIBUTE_INDEX_DATA_CHUNK_SIZE:
|
||||
fData->SetChunkSize(value.unsignedInt);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return AttributeHandler::HandleChildAttribute(context, type, typeIndex,
|
||||
|
@ -27,6 +27,11 @@
|
||||
|
||||
#include "FDCloser.h"
|
||||
#include "Stacker.h"
|
||||
#include "ZlibCompressor.h"
|
||||
|
||||
|
||||
// minimum length of data we require before trying to zlib compress them
|
||||
static const size_t kZlibCompressionSizeThreshold = 64;
|
||||
|
||||
|
||||
// #pragma mark - Data interface
|
||||
@ -536,7 +541,7 @@ PackageWriter::_Init(const char* fileName)
|
||||
throw std::bad_alloc();
|
||||
|
||||
// allocate data buffer
|
||||
fDataBufferSize = 128 * 1024;
|
||||
fDataBufferSize = 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
|
||||
fDataBuffer = malloc(fDataBufferSize);
|
||||
if (fDataBuffer == NULL)
|
||||
throw std::bad_alloc();
|
||||
@ -1144,13 +1149,51 @@ PackageWriter::_GetAttributeType(const char* attributeName, uint8 type)
|
||||
status_t
|
||||
PackageWriter::_AddData(Data& data, off_t size)
|
||||
{
|
||||
uint64 dataOffset = fHeapEnd - fHeapOffset;
|
||||
uint64 dataOffset = fHeapEnd;
|
||||
|
||||
uint64 compression = B_HPKG_COMPRESSION_NONE;
|
||||
uint64 compressedSize;
|
||||
|
||||
status_t error = _WriteZlibCompressedData(data, size, dataOffset,
|
||||
compressedSize);
|
||||
if (error == B_OK) {
|
||||
compression = B_HPKG_COMPRESSION_ZLIB;
|
||||
} else {
|
||||
error = _WriteUncompressedData(data, size, dataOffset);
|
||||
compressedSize = size;
|
||||
}
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
fHeapEnd = dataOffset + compressedSize;
|
||||
|
||||
// add data attribute
|
||||
Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA,
|
||||
compressedSize, dataOffset - fHeapOffset);
|
||||
Stacker<Attribute> attributeAttributeStacker(fTopAttribute, dataAttribute);
|
||||
|
||||
// if compressed, add compression attributes
|
||||
if (compression != B_HPKG_COMPRESSION_NONE) {
|
||||
_AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_COMPRESSION, compression);
|
||||
_AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size);
|
||||
// uncompressed size
|
||||
}
|
||||
|
||||
// TODO: Support inline data!
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageWriter::_WriteUncompressedData(Data& data, off_t size,
|
||||
uint64 writeOffset)
|
||||
{
|
||||
// copy the data to the heap
|
||||
off_t readOffset = 0;
|
||||
off_t remainingSize = size;
|
||||
while (remainingSize > 0) {
|
||||
// read from FD
|
||||
// read data
|
||||
size_t toCopy = std::min(remainingSize, (off_t)fDataBufferSize);
|
||||
ssize_t bytesRead = data.Read(fDataBuffer, toCopy, readOffset);
|
||||
if (bytesRead < 0) {
|
||||
@ -1164,8 +1207,7 @@ PackageWriter::_AddData(Data& data, off_t size)
|
||||
}
|
||||
|
||||
// write to heap
|
||||
ssize_t bytesWritten = pwrite(fFD, fDataBuffer, bytesRead,
|
||||
fHeapEnd);
|
||||
ssize_t bytesWritten = pwrite(fFD, fDataBuffer, bytesRead, writeOffset);
|
||||
if (bytesWritten < 0) {
|
||||
fprintf(stderr, "Error: Failed to write data: %s\n",
|
||||
strerror(errno));
|
||||
@ -1178,19 +1220,118 @@ PackageWriter::_AddData(Data& data, off_t size)
|
||||
|
||||
remainingSize -= bytesRead;
|
||||
readOffset += bytesRead;
|
||||
fHeapEnd += bytesRead;
|
||||
writeOffset += bytesRead;
|
||||
}
|
||||
|
||||
// add data attribute
|
||||
Attribute* dataAttribute = _AddDataAttribute(B_HPKG_ATTRIBUTE_NAME_DATA,
|
||||
size, dataOffset);
|
||||
Stacker<Attribute> attributeAttributeStacker(fTopAttribute, dataAttribute);
|
||||
|
||||
// _AddAttribute(B_HPKG_ATTRIBUTE_NAME_DATA_SIZE, (uint64)size);
|
||||
// uncompressed size -- not required for uncompressed data
|
||||
|
||||
// TODO: Support inline data!
|
||||
// TODO: Support compression!
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageWriter::_WriteZlibCompressedData(Data& data, off_t size,
|
||||
uint64 writeOffset, uint64& _compressedSize)
|
||||
{
|
||||
// Use zlib compression only for data large enough.
|
||||
if (size < kZlibCompressionSizeThreshold)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// fDataBuffer is 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, so split it into
|
||||
// two halves we can use for reading and compressing
|
||||
const size_t chunkSize = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
|
||||
uint8* inputBuffer = (uint8*)fDataBuffer;
|
||||
uint8* outputBuffer = (uint8*)fDataBuffer + chunkSize;
|
||||
|
||||
// account for the offset table
|
||||
uint64 chunkCount = (size + (chunkSize - 1)) / chunkSize;
|
||||
off_t offsetTableOffset = writeOffset;
|
||||
uint64* offsetTable = NULL;
|
||||
if (chunkCount > 1) {
|
||||
offsetTable = new uint64[chunkCount - 1];
|
||||
writeOffset = offsetTableOffset + (chunkCount - 1) * sizeof(uint64);
|
||||
}
|
||||
ArrayDeleter<uint64> offsetTableDeleter(offsetTable);
|
||||
|
||||
const uint64 dataOffset = writeOffset;
|
||||
const uint64 dataEndLimit = offsetTableOffset + size;
|
||||
|
||||
// read the data, compress them and write them to the heap
|
||||
off_t readOffset = 0;
|
||||
off_t remainingSize = size;
|
||||
uint64 chunkIndex = 0;
|
||||
while (remainingSize > 0) {
|
||||
// read data
|
||||
size_t toCopy = std::min(remainingSize, (off_t)chunkSize);
|
||||
ssize_t bytesRead = data.Read(inputBuffer, toCopy, readOffset);
|
||||
if (bytesRead < 0) {
|
||||
fprintf(stderr, "Error: Failed to read data: %s\n",
|
||||
strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
if ((size_t)bytesRead != toCopy) {
|
||||
fprintf(stderr, "Error: Failed to read all data\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// compress
|
||||
ZlibCompressor compressor;
|
||||
size_t compressedSize;
|
||||
status_t error = compressor.Compress(inputBuffer, bytesRead,
|
||||
outputBuffer, bytesRead, compressedSize);
|
||||
|
||||
const void* writeBuffer;
|
||||
size_t bytesToWrite;
|
||||
if (error == B_OK) {
|
||||
writeBuffer = outputBuffer;
|
||||
bytesToWrite = compressedSize;
|
||||
} else {
|
||||
if (error != B_BUFFER_OVERFLOW)
|
||||
return error;
|
||||
writeBuffer = inputBuffer;
|
||||
bytesToWrite = bytesRead;
|
||||
}
|
||||
|
||||
// check the total compressed data size
|
||||
if (writeOffset + bytesToWrite >= dataEndLimit)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
if (chunkIndex > 0)
|
||||
offsetTable[chunkIndex - 1] = writeOffset - dataOffset;
|
||||
|
||||
// write to heap
|
||||
ssize_t bytesWritten = pwrite(fFD, writeBuffer, bytesToWrite,
|
||||
writeOffset);
|
||||
if (bytesWritten < 0) {
|
||||
fprintf(stderr, "Error: Failed to write data: %s\n",
|
||||
strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
if ((size_t)bytesWritten != bytesToWrite) {
|
||||
fprintf(stderr, "Error: Failed to write all data\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
remainingSize -= bytesRead;
|
||||
readOffset += bytesRead;
|
||||
writeOffset += bytesToWrite;
|
||||
chunkIndex++;
|
||||
}
|
||||
|
||||
// write the offset table
|
||||
if (chunkCount > 1) {
|
||||
size_t bytesToWrite = (chunkCount - 1) * sizeof(uint64);
|
||||
ssize_t bytesWritten = pwrite(fFD, offsetTable, bytesToWrite,
|
||||
offsetTableOffset);
|
||||
if (bytesWritten < 0) {
|
||||
fprintf(stderr, "Error: Failed to write data: %s\n",
|
||||
strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
if ((size_t)bytesWritten != bytesToWrite) {
|
||||
fprintf(stderr, "Error: Failed to write all data\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
_compressedSize = writeOffset - dataOffset;
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -83,6 +83,11 @@ private:
|
||||
uint8 type);
|
||||
|
||||
status_t _AddData(Data& data, off_t size);
|
||||
status_t _WriteUncompressedData(Data& data, off_t size,
|
||||
uint64 writeOffset);
|
||||
status_t _WriteZlibCompressedData(Data& data, off_t size,
|
||||
uint64 writeOffset,
|
||||
uint64& _compressedSize);
|
||||
|
||||
private:
|
||||
const char* fFileName;
|
||||
|
40
src/bin/package/compression/ZlibCompressionBase.cpp
Normal file
40
src/bin/package/compression/ZlibCompressionBase.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ZlibCompressionBase.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
/*static*/ status_t
|
||||
ZlibCompressionBase::TranslateZlibError(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case Z_OK:
|
||||
return B_OK;
|
||||
case Z_STREAM_END:
|
||||
case Z_NEED_DICT:
|
||||
// a special event (no error), but the caller doesn't seem to handle
|
||||
// it
|
||||
return B_ERROR;
|
||||
case Z_ERRNO:
|
||||
return errno;
|
||||
case Z_STREAM_ERROR:
|
||||
return B_BAD_VALUE;
|
||||
case Z_DATA_ERROR:
|
||||
return B_BAD_DATA;
|
||||
case Z_MEM_ERROR:
|
||||
return B_NO_MEMORY;
|
||||
case Z_BUF_ERROR:
|
||||
return B_BUFFER_OVERFLOW;
|
||||
case Z_VERSION_ERROR:
|
||||
return B_BAD_VALUE;
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
18
src/bin/package/compression/ZlibCompressionBase.h
Normal file
18
src/bin/package/compression/ZlibCompressionBase.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ZLIB_COMPRESSION_BASE_H
|
||||
#define ZLIB_COMPRESSION_BASE_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
class ZlibCompressionBase {
|
||||
public:
|
||||
static status_t TranslateZlibError(int error);
|
||||
};
|
||||
|
||||
|
||||
#endif // ZLIB_COMPRESSION_BASE_H
|
74
src/bin/package/compression/ZlibCompressor.cpp
Normal file
74
src/bin/package/compression/ZlibCompressor.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ZlibDecompressor.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
ZlibDecompressor::ZlibDecompressor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ZlibDecompressor::~ZlibDecompressor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output,
|
||||
size_t outputSize, size_t& _uncompressedSize)
|
||||
{
|
||||
if (inputSize == 0 || outputSize == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare stream
|
||||
z_stream zStream = {
|
||||
(Bytef*)input, // next_in
|
||||
inputSize, // avail_in
|
||||
0, // total_in
|
||||
(Bytef*)output, // next_out
|
||||
outputSize, // avail_out
|
||||
0, // total_out
|
||||
0, // msg
|
||||
0, // state;
|
||||
Z_NULL, // zalloc
|
||||
Z_NULL, // zfree
|
||||
Z_NULL, // opaque
|
||||
0, // data_type
|
||||
0, // adler
|
||||
0 // reserved
|
||||
};
|
||||
|
||||
int zlibError = inflateInit(&zStream);
|
||||
if (zlibError != Z_OK)
|
||||
return TranslateZlibError(zlibError);
|
||||
|
||||
|
||||
// deflate
|
||||
status_t error = B_OK;
|
||||
zlibError = inflate(&zStream, Z_FINISH);
|
||||
if (zlibError != Z_STREAM_END) {
|
||||
if (zlibError == Z_OK)
|
||||
error = B_BUFFER_OVERFLOW;
|
||||
else
|
||||
error = TranslateZlibError(zlibError);
|
||||
}
|
||||
|
||||
// clean up
|
||||
zlibError = inflateEnd(&zStream);
|
||||
if (zlibError != Z_OK && error == B_OK)
|
||||
error = TranslateZlibError(zlibError);
|
||||
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
_uncompressedSize = zStream.total_out;
|
||||
return B_OK;
|
||||
}
|
23
src/bin/package/compression/ZlibCompressor.h
Normal file
23
src/bin/package/compression/ZlibCompressor.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ZLIB_COMPRESSOR_H
|
||||
#define ZLIB_COMPRESSOR_H
|
||||
|
||||
|
||||
#include "ZlibCompressionBase.h"
|
||||
|
||||
|
||||
class ZlibCompressor : public ZlibCompressionBase {
|
||||
public:
|
||||
ZlibCompressor();
|
||||
~ZlibCompressor();
|
||||
|
||||
status_t Compress(const void* input, size_t inputSize,
|
||||
void* output, size_t outputSize,
|
||||
size_t& _compressedSize);
|
||||
};
|
||||
|
||||
|
||||
#endif // ZLIB_COMPRESSOR_H
|
73
src/bin/package/compression/ZlibDecompressor.cpp
Normal file
73
src/bin/package/compression/ZlibDecompressor.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ZlibCompressor.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
||||
ZlibCompressor::ZlibCompressor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ZlibCompressor::~ZlibCompressor()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ZlibCompressor::Compress(const void* input, size_t inputSize, void* output,
|
||||
size_t outputSize, size_t& _compressedSize)
|
||||
{
|
||||
if (inputSize == 0 || outputSize == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// prepare stream
|
||||
z_stream zStream = {
|
||||
(Bytef*)input, // next_in
|
||||
inputSize, // avail_in
|
||||
0, // total_in
|
||||
(Bytef*)output, // next_out
|
||||
outputSize, // avail_out
|
||||
0, // total_out
|
||||
0, // msg
|
||||
0, // state;
|
||||
Z_NULL, // zalloc
|
||||
Z_NULL, // zfree
|
||||
Z_NULL, // opaque
|
||||
0, // data_type
|
||||
0, // adler
|
||||
0 // reserved
|
||||
};
|
||||
|
||||
int zlibError = deflateInit(&zStream, Z_BEST_COMPRESSION);
|
||||
if (zlibError != Z_OK)
|
||||
return TranslateZlibError(zlibError);
|
||||
|
||||
// deflate
|
||||
status_t error = B_OK;
|
||||
zlibError = deflate(&zStream, Z_FINISH);
|
||||
if (zlibError != Z_STREAM_END) {
|
||||
if (zlibError == Z_OK)
|
||||
error = B_BUFFER_OVERFLOW;
|
||||
else
|
||||
error = TranslateZlibError(zlibError);
|
||||
}
|
||||
|
||||
// clean up
|
||||
zlibError = deflateEnd(&zStream);
|
||||
if (zlibError != Z_OK && error == B_OK)
|
||||
error = TranslateZlibError(zlibError);
|
||||
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
_compressedSize = zStream.total_out;
|
||||
return B_OK;
|
||||
}
|
23
src/bin/package/compression/ZlibDecompressor.h
Normal file
23
src/bin/package/compression/ZlibDecompressor.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ZLIB_DECOMPRESSOR_H
|
||||
#define ZLIB_DECOMPRESSOR_H
|
||||
|
||||
|
||||
#include "ZlibCompressionBase.h"
|
||||
|
||||
|
||||
class ZlibDecompressor : public ZlibCompressionBase {
|
||||
public:
|
||||
ZlibDecompressor();
|
||||
~ZlibDecompressor();
|
||||
|
||||
status_t Decompress(const void* input, size_t inputSize,
|
||||
void* output, size_t outputSize,
|
||||
size_t& _uncompressedSize);
|
||||
};
|
||||
|
||||
|
||||
#endif // ZLIB_DECOMPRESSOR_H
|
Loading…
Reference in New Issue
Block a user