* Added support for iterative operation to ZlibCompressor/ZlibDecompressor.

* Added support for compressing/decompressing the TOC section of the package
  to PackageWriter/PackageReader.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34063 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-11-15 21:29:53 +00:00
parent 5e5a7d535c
commit 689605bf2a
12 changed files with 686 additions and 100 deletions

View File

@ -0,0 +1,44 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "DataOutput.h"
#include <string.h>
// #pragma mark - DataOutput
DataOutput::~DataOutput()
{
}
// #pragma mark - BufferDataOutput
BufferDataOutput::BufferDataOutput(void* buffer, size_t size)
:
fBuffer(buffer),
fSize(size),
fBytesWritten(0)
{
}
status_t
BufferDataOutput::WriteData(const void* buffer, size_t size)
{
if (size == 0)
return B_OK;
if (size > fSize - fBytesWritten)
return B_BAD_VALUE;
memcpy((uint8*)fBuffer + fBytesWritten, buffer, size);
fBytesWritten += size;
return B_OK;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef DATA_OUTPUT_H
#define DATA_OUTPUT_H
#include <SupportDefs.h>
class DataOutput {
public:
virtual ~DataOutput();
virtual status_t WriteData(const void* buffer, size_t size) = 0;
};
class BufferDataOutput : public DataOutput {
public:
BufferDataOutput(void* buffer, size_t size);
size_t BytesWritten() const { return fBytesWritten; }
virtual status_t WriteData(const void* buffer, size_t size);
private:
void* fBuffer;
size_t fSize;
size_t fBytesWritten;
};
#endif // DATA_OUTPUT_H

View File

@ -14,6 +14,7 @@ BinCommand package :
command_dump.cpp
command_extract.cpp
command_list.cpp
DataOutput.cpp
DataReader.cpp
package.cpp
PackageData.cpp

View File

@ -236,8 +236,9 @@ private:
return error;
size_t actuallyUncompressedSize;
error = ZlibDecompressor().Decompress(fReadBuffer, compressedSize,
fUncompressBuffer, uncompressedSize, actuallyUncompressedSize);
error = ZlibDecompressor::DecompressSingleBuffer(fReadBuffer,
compressedSize, fUncompressBuffer, uncompressedSize,
actuallyUncompressedSize);
if (error == B_OK && actuallyUncompressedSize != uncompressedSize)
error = B_BAD_DATA;
}

View File

@ -14,20 +14,25 @@
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <new>
#include <ByteOrder.h>
#include <haiku_package.h>
#include "DataOutput.h"
#include "PackageData.h"
#include "PackageEntry.h"
#include "PackageEntryAttribute.h"
#include "ZlibDecompressor.h"
// maximum TOC size, we support reading
// maximum TOC size we support reading
static const size_t kMaxTOCSize = 64 * 1024 * 1024;
static const size_t kScratchBufferSize = 64 * 1024;
enum {
ATTRIBUTE_INDEX_DIRECTORY_ENTRY = 0,
@ -604,7 +609,9 @@ PackageReader::PackageReader()
fFD(-1),
fTOCSection(NULL),
fAttributeTypes(NULL),
fStrings(NULL)
fStrings(NULL),
fScratchBuffer(NULL),
fScratchBufferSize(0)
{
}
@ -614,6 +621,7 @@ PackageReader::~PackageReader()
if (fFD >= 0)
close(fFD);
delete[] fScratchBuffer;
delete[] fStrings;
delete[] fAttributeTypes;
delete[] fTOCSection;
@ -641,7 +649,7 @@ PackageReader::Init(const char* fileName)
// read the header
hpkg_header header;
status_t error = _ReadBuffer(&header, sizeof(header), 0);
status_t error = _ReadBuffer(0, &header, sizeof(header));
if (error != B_OK)
return error;
@ -751,6 +759,14 @@ PackageReader::Init(const char* fileName)
return B_UNSUPPORTED;
}
// allocate a scratch buffer
fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize];
if (fScratchBuffer == NULL) {
fprintf(stderr, "Error: Out of memory!\n");
return B_NO_MEMORY;
}
fScratchBufferSize = kScratchBufferSize;
// read in the complete TOC
fTOCSection = new(std::nothrow) uint8[fTOCUncompressedLength];
if (fTOCSection == NULL) {
@ -758,7 +774,8 @@ PackageReader::Init(const char* fileName)
return B_NO_MEMORY;
}
error = _ReadBuffer(fTOCSection, fTOCUncompressedLength, fTOCSectionOffset);
error = _ReadCompressedBuffer(fTOCSectionOffset, fTOCSection,
fTOCCompressedLength, fTOCUncompressedLength, fTOCCompression);
if (error != B_OK)
return error;
@ -1249,7 +1266,7 @@ PackageReader::_ReadTOCBuffer(void* buffer, size_t size)
status_t
PackageReader::_ReadBuffer(void* buffer, size_t size, off_t offset)
PackageReader::_ReadBuffer(off_t offset, void* buffer, size_t size)
{
ssize_t bytesRead = pread(fFD, buffer, size, offset);
if (bytesRead < 0) {
@ -1267,6 +1284,59 @@ PackageReader::_ReadBuffer(void* buffer, size_t size, off_t offset)
}
status_t
PackageReader::_ReadCompressedBuffer(off_t offset, void* buffer,
size_t compressedSize, size_t uncompressedSize, uint32 compression)
{
switch (compression) {
case B_HPKG_COMPRESSION_NONE:
return _ReadBuffer(offset, buffer, compressedSize);
case B_HPKG_COMPRESSION_ZLIB:
{
// init the decompressor
BufferDataOutput bufferOutput(buffer, uncompressedSize);
ZlibDecompressor decompressor(&bufferOutput);
status_t error = decompressor.Init();
if (error != B_OK)
return error;
while (compressedSize > 0) {
// read compressed buffer
size_t toRead = std::min(compressedSize, fScratchBufferSize);
error = _ReadBuffer(offset, fScratchBuffer, toRead);
if (error != B_OK)
return error;
// uncompress
error = decompressor.DecompressNext(fScratchBuffer, toRead);
if (error != B_OK)
return error;
compressedSize -= toRead;
offset += toRead;
}
error = decompressor.Finish();
if (error != B_OK)
return error;
// verify that all data have been read
if (bufferOutput.BytesWritten() != uncompressedSize) {
fprintf(stderr, "Error: Missing bytes in uncompressed "
"buffer!\n");
return B_BAD_DATA;
}
return B_OK;
}
default:
return B_BAD_DATA;
}
}
/*static*/ int8
PackageReader::_GetStandardIndex(const AttributeType* type)
{

View File

@ -104,8 +104,12 @@ private:
const void*& _buffer);
status_t _ReadTOCBuffer(void* buffer, size_t size);
status_t _ReadBuffer(void* buffer, size_t size,
off_t offset);
status_t _ReadBuffer(off_t offset, void* buffer,
size_t size);
status_t _ReadCompressedBuffer(off_t offset,
void* buffer, size_t compressedSize,
size_t uncompressedSize,
uint32 compression);
static int8 _GetStandardIndex(const AttributeType* type);
@ -141,6 +145,9 @@ private:
char** fStrings;
AttributeHandlerList* fAttributeHandlerStack;
uint8* fScratchBuffer;
size_t fScratchBufferSize;
};

View File

@ -25,6 +25,7 @@
#include <haiku_package.h>
#include "DataOutput.h"
#include "DataReader.h"
#include "FDCloser.h"
#include "Stacker.h"
@ -373,7 +374,149 @@ private:
};
// #pragma mark - PackageWriter
// #pragma mark - DataWriter
struct PackageWriter::DataWriter {
DataWriter()
:
fBytesWritten(0)
{
}
virtual ~DataWriter()
{
}
uint64 BytesWritten() const
{
return fBytesWritten;
}
virtual status_t WriteDataNoThrow(const void* buffer, size_t size) = 0;
inline void WriteDataThrows(const void* buffer, size_t size)
{
status_t error = WriteDataNoThrow(buffer, size);
if (error != B_OK)
throw status_t(error);
}
protected:
uint64 fBytesWritten;
};
struct PackageWriter::DummyDataWriter : DataWriter {
DummyDataWriter()
{
}
virtual status_t WriteDataNoThrow(const void* buffer, size_t size)
{
fBytesWritten += size;
return B_OK;
}
};
struct PackageWriter::FDDataWriter : DataWriter {
FDDataWriter(int fd, off_t offset)
:
fFD(fd),
fOffset(offset)
{
}
virtual status_t WriteDataNoThrow(const void* buffer, size_t size)
{
ssize_t bytesWritten = pwrite(fFD, buffer, size, fOffset);
if (bytesWritten < 0) {
fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write data: %s\n",
buffer, size, strerror(errno));
return errno;
}
if ((size_t)bytesWritten != size) {
fprintf(stderr, "_WriteBuffer(%p, %lu) failed to write all data\n",
buffer, size);
return B_ERROR;
}
fOffset += size;
fBytesWritten += size;
return B_OK;
}
off_t Offset() const
{
return fOffset;
}
private:
int fFD;
off_t fOffset;
};
struct PackageWriter::ZlibDataWriter : DataWriter, private DataOutput {
ZlibDataWriter(DataWriter* dataWriter)
:
fDataWriter(dataWriter),
fCompressor(this)
{
}
void Init()
{
status_t error = fCompressor.Init();
if (error != B_OK)
throw status_t(error);
}
void Finish()
{
status_t error = fCompressor.Finish();
if (error != B_OK)
throw status_t(error);
}
virtual status_t WriteDataNoThrow(const void* buffer, size_t size)
{
status_t error = fCompressor.CompressNext(buffer, size);
if (error == B_OK)
fBytesWritten += size;
return error;
}
private:
// DataOutput
virtual status_t WriteData(const void* buffer, size_t size)
{
return fDataWriter->WriteDataNoThrow(buffer, size);
}
private:
DataWriter* fDataWriter;
ZlibCompressor fCompressor;
};
// #pragma mark - PackageWriter (Inline Methods)
template<typename Type>
inline void
PackageWriter::_Write(const Type& value)
{
fDataWriter->WriteDataThrows(&value, sizeof(Type));
}
inline void
PackageWriter::_WriteString(const char* string)
{
fDataWriter->WriteDataThrows(string, strlen(string) + 1);
}
template<typename Type>
@ -386,12 +529,16 @@ PackageWriter::_AddAttribute(const char* attributeName, Type value)
}
// #pragma mark - PackageWriter
PackageWriter::PackageWriter()
:
fFileName(NULL),
fFD(-1),
fFinished(false),
fDataBuffer(NULL),
fDataWriter(NULL),
fRootEntry(NULL),
fRootAttribute(NULL),
fTopAttribute(NULL),
@ -529,26 +676,11 @@ PackageWriter::_Finish()
printf("header size: %lu\n", sizeof(hpkg_header));
printf("heap size: %lld\n", fHeapEnd - sizeof(hpkg_header));
// write the attribute type abbreviations
off_t attributeTypesOffset = fHeapEnd;
_WriteAttributeTypes();
printf("attributes types size: %lld\n", fHeapEnd - attributeTypesOffset);
hpkg_header header;
// write the cached strings
off_t cachedStringsOffset = fHeapEnd;
int32 cachedStringsWritten = _WriteCachedStrings();
printf("cached strings size: %lld\n", fHeapEnd - cachedStringsOffset);
// write the TOC
off_t tocOffset = fHeapEnd;
_WriteAttributeChildren(fRootAttribute);
printf("toc size: %lld\n", fHeapEnd - tocOffset);
// write the package attributes
off_t packageAttributesOffset = fHeapEnd;
_Write<uint8>(0);
// TODO: Write them for real!
printf("package attributes size: %lld\n", fHeapEnd - packageAttributesOffset);
// write the TOC and package attributes
_WriteTOC(header);
_WritePackageAttributes(header);
off_t totalSize = fHeapEnd;
printf("total size: %lld\n", totalSize);
@ -556,38 +688,12 @@ printf("total size: %lld\n", totalSize);
// prepare the header
// general
hpkg_header header;
header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
header.header_size = B_HOST_TO_BENDIAN_INT16(
(uint16)sizeof(hpkg_header));
header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
// package attributes
header.attributes_compression = B_HOST_TO_BENDIAN_INT32(
B_HPKG_COMPRESSION_NONE);
header.attributes_length_compressed
= B_HOST_TO_BENDIAN_INT32(fHeapEnd - packageAttributesOffset);
header.attributes_length_uncompressed
= header.attributes_length_compressed;
// TODO: Support compression!
// TOC
header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_NONE);
header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
packageAttributesOffset - attributeTypesOffset);
header.toc_length_uncompressed = header.toc_length_compressed;
// TODO: Support compression!
// TOC subsections
header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64(
cachedStringsOffset - attributeTypesOffset);
header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64(
fAttributeTypes->CountElements());
header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
tocOffset - cachedStringsOffset);
header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
// write the header
_WriteBuffer(&header, sizeof(hpkg_header), 0);
@ -666,6 +772,79 @@ PackageWriter::_RegisterEntry(Entry* parent, const char* name,
}
void
PackageWriter::_WriteTOC(hpkg_header& header)
{
// prepare the writer (zlib writer on top of a file writer)
off_t startOffset = fHeapEnd;
FDDataWriter realWriter(fFD, startOffset);
ZlibDataWriter zlibWriter(&realWriter);
fDataWriter = &zlibWriter;
zlibWriter.Init();
// write the sections
uint64 uncompressedAttributeTypesSize;
uint64 uncompressedStringsSize;
uint64 uncompressedMainSize;
int32 cachedStringsWritten = _WriteTOCSections(
uncompressedAttributeTypesSize, uncompressedStringsSize,
uncompressedMainSize);
// finish the writer
zlibWriter.Finish();
fHeapEnd = realWriter.Offset();
fDataWriter = NULL;
printf("attributes types size: %llu\n", uncompressedAttributeTypesSize);
printf("cached strings size: %llu\n", uncompressedStringsSize);
printf("TOC main size: %llu\n", uncompressedMainSize);
off_t endOffset = fHeapEnd;
printf("total TOC size: %llu (%llu)\n", endOffset - startOffset, zlibWriter.BytesWritten());
// update the header
// TOC
header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
endOffset - startOffset);
header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64(
zlibWriter.BytesWritten());
// TOC subsections
header.toc_attribute_types_length = B_HOST_TO_BENDIAN_INT64(
uncompressedAttributeTypesSize);
header.toc_attribute_types_count = B_HOST_TO_BENDIAN_INT64(
fAttributeTypes->CountElements());
header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
uncompressedStringsSize);
header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
}
int32
PackageWriter::_WriteTOCSections(uint64& _attributeTypesSize,
uint64& _stringsSize, uint64& _mainSize)
{
// write the attribute type abbreviations
uint64 attributeTypesOffset = fDataWriter->BytesWritten();
_WriteAttributeTypes();
// write the cached strings
uint64 cachedStringsOffset = fDataWriter->BytesWritten();
int32 cachedStringsWritten = _WriteCachedStrings();
// write the main TOC section
uint64 mainOffset = fDataWriter->BytesWritten();
_WriteAttributeChildren(fRootAttribute);
_attributeTypesSize = cachedStringsOffset - attributeTypesOffset;
_stringsSize = mainOffset - cachedStringsOffset;
_mainSize = fDataWriter->BytesWritten() - mainOffset;
return cachedStringsWritten;
}
void
PackageWriter::_WriteAttributeTypes()
{
@ -762,6 +941,34 @@ PackageWriter::_WriteAttributeChildren(Attribute* attribute)
}
void
PackageWriter::_WritePackageAttributes(hpkg_header& header)
{
// write the package attributes
off_t startOffset = fHeapEnd;
FDDataWriter realWriter(fFD, startOffset);
fDataWriter = &realWriter;
_Write<uint8>(0);
// TODO: Write them for real!
fHeapEnd = realWriter.Offset();
fDataWriter = NULL;
off_t endOffset = fHeapEnd;
printf("package attributes size: %lld\n", endOffset - startOffset);
// update the header
header.attributes_compression = B_HOST_TO_BENDIAN_INT32(
B_HPKG_COMPRESSION_NONE);
header.attributes_length_compressed
= B_HOST_TO_BENDIAN_INT32(endOffset - startOffset);
header.attributes_length_uncompressed
= header.attributes_length_compressed;
// TODO: Support compression!
}
void
PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding)
{
@ -815,7 +1022,7 @@ PackageWriter::_WriteAttributeValue(const AttributeValue& value, uint8 encoding)
if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP)
_WriteUnsignedLEB128(value.data.offset);
else
_WriteBuffer(value.data.raw, value.data.size);
fDataWriter->WriteDataThrows(value.data.raw, value.data.size);
break;
}
@ -838,7 +1045,7 @@ PackageWriter::_WriteUnsignedLEB128(uint64 value)
bytes[count++] = byte | (value != 0 ? 0x80 : 0);
} while (value != 0);
_WriteBuffer(bytes, count);
fDataWriter->WriteDataThrows(bytes, count);
}
@ -1237,10 +1444,9 @@ PackageWriter::_WriteZlibCompressedData(DataReader& dataReader, off_t size,
}
// compress
ZlibCompressor compressor;
size_t compressedSize;
error = compressor.Compress(inputBuffer, toCopy, outputBuffer,
toCopy, compressedSize);
error = ZlibCompressor::CompressSingleBuffer(inputBuffer, toCopy,
outputBuffer, toCopy, compressedSize);
const void* writeBuffer;
size_t bytesToWrite;

View File

@ -13,6 +13,7 @@
class DataReader;
struct hpkg_header;
class PackageWriter {
@ -32,6 +33,10 @@ private:
struct Attribute;
struct AttributeTypeUsageGreater;
struct Entry;
struct DataWriter;
struct DummyDataWriter;
struct FDDataWriter;
struct ZlibDataWriter;
typedef BOpenHashTable<AttributeTypeHashDefinition>
AttributeTypeTable;
@ -46,10 +51,15 @@ private:
const char* name, size_t nameLength,
bool isImplicit);
void _WriteTOC(hpkg_header& header);
int32 _WriteTOCSections(uint64& _attributeTypesSize,
uint64& _stringsSize, uint64& _mainSize);
void _WriteAttributeTypes();
int32 _WriteCachedStrings();
void _WriteAttributeChildren(Attribute* attribute);
void _WritePackageAttributes(hpkg_header& header);
void _WriteAttributeValue(
const AttributeValue& value,
uint8 encoding);
@ -61,7 +71,6 @@ private:
void _WriteBuffer(const void* buffer, size_t size,
off_t offset);
inline void _WriteBuffer(const void* buffer, size_t size);
void _AddEntry(int dirFD, Entry* entry,
const char* fileName);
@ -100,6 +109,8 @@ private:
void* fDataBuffer;
size_t fDataBufferSize;
DataWriter* fDataWriter;
Entry* fRootEntry;
Attribute* fRootAttribute;
@ -110,27 +121,4 @@ private:
};
template<typename Type>
inline void
PackageWriter::_Write(const Type& value)
{
_WriteBuffer(&value, sizeof(Type));
}
inline void
PackageWriter::_WriteString(const char* string)
{
_WriteBuffer(string, strlen(string) + 1);
}
inline void
PackageWriter::_WriteBuffer(const void* buffer, size_t size)
{
_WriteBuffer(buffer, size, fHeapEnd);
fHeapEnd += size;
}
#endif // PACKAGE_WRITER_H

View File

@ -7,23 +7,121 @@
#include "ZlibCompressor.h"
#include <errno.h>
#include <stdio.h>
#include <zlib.h>
#include "DataOutput.h"
ZlibCompressor::ZlibCompressor()
static const size_t kOutputBufferSize = 1024;
ZlibCompressor::ZlibCompressor(DataOutput* output)
:
fOutput(output),
fStreamInitialized(false)
{
}
ZlibCompressor::~ZlibCompressor()
{
if (fStreamInitialized)
deflateEnd(&fStream);
}
status_t
ZlibCompressor::Compress(const void* input, size_t inputSize, void* output,
size_t outputSize, size_t& _compressedSize)
ZlibCompressor::Init()
{
// initialize the stream
fStream.next_in = NULL;
fStream.avail_in = 0;
fStream.total_in = 0;
fStream.next_out = NULL;
fStream.avail_out = 0;
fStream.total_out = 0;
fStream.msg = 0;
fStream.state = 0;
fStream.zalloc = Z_NULL;
fStream.zfree = Z_NULL;
fStream.opaque = Z_NULL;
fStream.data_type = 0;
fStream.adler = 0;
fStream.reserved = 0;
int zlibError = deflateInit(&fStream, Z_BEST_COMPRESSION);
if (zlibError != Z_OK)
return TranslateZlibError(zlibError);
fStreamInitialized = true;
return B_OK;
}
status_t
ZlibCompressor::CompressNext(const void* input, size_t inputSize)
{
fStream.next_in = (Bytef*)input;
fStream.avail_in = inputSize;
while (fStream.avail_in > 0) {
uint8 outputBuffer[kOutputBufferSize];
fStream.next_out = (Bytef*)outputBuffer;
fStream.avail_out = sizeof(outputBuffer);
int zlibError = deflate(&fStream, 0);
if (zlibError != Z_OK)
return TranslateZlibError(zlibError);
if (fStream.avail_out < sizeof(outputBuffer)) {
status_t error = fOutput->WriteData(outputBuffer,
sizeof(outputBuffer) - fStream.avail_out);
if (error != B_OK)
return error;
}
}
return B_OK;
}
status_t
ZlibCompressor::Finish()
{
fStream.next_in = (Bytef*)NULL;
fStream.avail_in = 0;
while (true) {
uint8 outputBuffer[kOutputBufferSize];
fStream.next_out = (Bytef*)outputBuffer;
fStream.avail_out = sizeof(outputBuffer);
int zlibError = deflate(&fStream, Z_FINISH);
if (zlibError != Z_OK && zlibError != Z_STREAM_END)
return TranslateZlibError(zlibError);
if (fStream.avail_out < sizeof(outputBuffer)) {
status_t error = fOutput->WriteData(outputBuffer,
sizeof(outputBuffer) - fStream.avail_out);
if (error != B_OK)
return error;
}
if (zlibError == Z_STREAM_END)
break;
}
deflateEnd(&fStream);
fStreamInitialized = false;
return B_OK;
}
/*static*/ status_t
ZlibCompressor::CompressSingleBuffer(const void* input, size_t inputSize,
void* output, size_t outputSize, size_t& _compressedSize)
{
if (inputSize == 0 || outputSize == 0)
return B_BAD_VALUE;

View File

@ -6,17 +6,32 @@
#define ZLIB_COMPRESSOR_H
#include <zlib.h>
#include "ZlibCompressionBase.h"
class DataOutput;
class ZlibCompressor : public ZlibCompressionBase {
public:
ZlibCompressor();
ZlibCompressor(DataOutput* output);
~ZlibCompressor();
status_t Compress(const void* input, size_t inputSize,
void* output, size_t outputSize,
size_t& _compressedSize);
status_t Init();
status_t CompressNext(const void* input,
size_t inputSize);
status_t Finish();
static status_t CompressSingleBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize, size_t& _compressedSize);
private:
z_stream fStream;
DataOutput* fOutput;
bool fStreamInitialized;
};

View File

@ -7,23 +7,127 @@
#include "ZlibDecompressor.h"
#include <errno.h>
#include <stdio.h>
#include <zlib.h>
#include "DataOutput.h"
ZlibDecompressor::ZlibDecompressor()
// TODO: For the kernel the buffer shouldn't be allocated on the stack.
static const size_t kOutputBufferSize = 1024;
ZlibDecompressor::ZlibDecompressor(DataOutput* output)
:
fOutput(output),
fStreamInitialized(false),
fFinished(false)
{
}
ZlibDecompressor::~ZlibDecompressor()
{
if (fStreamInitialized)
inflateEnd(&fStream);
}
status_t
ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output,
size_t outputSize, size_t& _uncompressedSize)
ZlibDecompressor::Init()
{
// initialize the stream
fStream.next_in = NULL;
fStream.avail_in = 0;
fStream.total_in = 0;
fStream.next_out = NULL;
fStream.avail_out = 0;
fStream.total_out = 0;
fStream.msg = 0;
fStream.state = 0;
fStream.zalloc = Z_NULL;
fStream.zfree = Z_NULL;
fStream.opaque = Z_NULL;
fStream.data_type = 0;
fStream.adler = 0;
fStream.reserved = 0;
int zlibError = inflateInit(&fStream);
if (zlibError != Z_OK)
return TranslateZlibError(zlibError);
fStreamInitialized = true;
return B_OK;
}
status_t
ZlibDecompressor::DecompressNext(const void* input, size_t inputSize)
{
fStream.next_in = (Bytef*)input;
fStream.avail_in = inputSize;
while (fStream.avail_in > 0) {
if (fFinished)
return B_BAD_DATA;
uint8 outputBuffer[kOutputBufferSize];
fStream.next_out = (Bytef*)outputBuffer;
fStream.avail_out = sizeof(outputBuffer);
int zlibError = inflate(&fStream, 0);
if (zlibError == Z_STREAM_END)
fFinished = true;
else if (zlibError != Z_OK)
return TranslateZlibError(zlibError);
if (fStream.avail_out < sizeof(outputBuffer)) {
status_t error = fOutput->WriteData(outputBuffer,
sizeof(outputBuffer) - fStream.avail_out);
if (error != B_OK)
return error;
}
}
return B_OK;
}
status_t
ZlibDecompressor::Finish()
{
fStream.next_in = (Bytef*)NULL;
fStream.avail_in = 0;
while (!fFinished) {
uint8 outputBuffer[kOutputBufferSize];
fStream.next_out = (Bytef*)outputBuffer;
fStream.avail_out = sizeof(outputBuffer);
int zlibError = inflate(&fStream, Z_FINISH);
if (zlibError == Z_STREAM_END)
fFinished = true;
else if (zlibError != Z_OK)
return TranslateZlibError(zlibError);
if (fStream.avail_out < sizeof(outputBuffer)) {
status_t error = fOutput->WriteData(outputBuffer,
sizeof(outputBuffer) - fStream.avail_out);
if (error != B_OK)
return error;
}
}
inflateEnd(&fStream);
fStreamInitialized = false;
return B_OK;
}
/*static*/ status_t
ZlibDecompressor::DecompressSingleBuffer(const void* input, size_t inputSize,
void* output, size_t outputSize, size_t& _uncompressedSize)
{
if (inputSize == 0 || outputSize == 0)
return B_BAD_VALUE;
@ -51,7 +155,7 @@ ZlibDecompressor::Decompress(const void* input, size_t inputSize, void* output,
return TranslateZlibError(zlibError);
// deflate
// inflate
status_t error = B_OK;
zlibError = inflate(&zStream, Z_FINISH);
if (zlibError != Z_STREAM_END) {

View File

@ -6,17 +6,34 @@
#define ZLIB_DECOMPRESSOR_H
#include <zlib.h>
#include "ZlibCompressionBase.h"
class DataOutput;
class ZlibDecompressor : public ZlibCompressionBase {
public:
ZlibDecompressor();
ZlibDecompressor(DataOutput* output);
~ZlibDecompressor();
status_t Decompress(const void* input, size_t inputSize,
void* output, size_t outputSize,
status_t Init();
status_t DecompressNext(const void* input,
size_t inputSize);
status_t Finish();
static status_t DecompressSingleBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize,
size_t& _uncompressedSize);
private:
z_stream fStream;
DataOutput* fOutput;
bool fStreamInitialized;
bool fFinished;
};