/*
DevelopDotNet
http://www.developdotnet.com
File Created by: Alberto Ferrazzoli
Date: 14/06/2004
Description:
ZCompressor provide direct buffer compress/uncompress functionality
Notes:
Revision Log - Please mark significant changes in source code in the following format:
Date - Time - Reviewer - Comments
09/07/2004 Alberto Ferrazzoli Fix _uncompress throw exception for inflate data error
*/
#include "StdAfx.h"
#include "RS.h"
#include ".\zcompressor.h"
#include "ZStream.h"
#include <vector>
#using <mscorlib.dll>
using namespace DevelopDotNet::Compression;
ZCompressor::ZCompressor()
{
Init(false, NULL);
}
ZCompressor::ZCompressor(bool raw)
{
Init(raw, NULL);
}
ZCompressor::ZCompressor(bool raw, IChecksum* checksum)
{
Init(raw, checksum);
}
void ZCompressor::Init(bool raw, IChecksum* checksum)
{
_raw = raw;
_checksum = checksum;
}
System::Byte ZCompressor::Compress(System::Byte source __gc[]) __gc[]
{
return Compress(source, CompressionLevel::Normal);
}
System::Byte ZCompressor::Compress(System::Byte source __gc[], CompressionLevel level) __gc[]
{
if(NULL == source)
{
throw __gc new ArgumentNullException(S"source");
}
if(source->Length == 0)
{
return __gc new System::Byte[0];
}
System::Byte buffer __gc [] =
_compress(&source[0], source->Length, level);
return buffer;
}
System::Byte ZCompressor::_compress(unsigned char __gc *source, unsigned long sourceLen, CompressionLevel level) __gc []
{
uLong length = compressBound(sourceLen);
System::Byte buffer __gc[] = __gc new System::Byte[length];
BYTE __pin * pBuffer = &buffer[0];
BYTE __pin * pSource = &source[0];
int nRes = compress2(pBuffer, &length, pSource, sourceLen, level);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Compress error");
}
System::Byte dest __gc[] = __gc new System::Byte[length];
System::Buffer::BlockCopy(buffer, 0, dest, 0, length);
return dest;
}
System::Byte ZCompressor::Uncompress(System::Byte source __gc[]) __gc[]
{
if(NULL == source)
{
throw __gc new ArgumentNullException(S"source");
}
if(source->Length == 0)
{
return __gc new System::Byte[0];
}
System::Byte buffer __gc[] = _uncompress(&source[0], source->Length);
return buffer;
}
System::Byte ZCompressor::_uncompress(unsigned char __gc *source, unsigned long sourceLen) __gc []
{
std::vector<BYTE *> buffers;
int nRes = Z_OK;
z_stream zcpr;
long lOrigToDo = sourceLen;
long lOrigDone = 0;
memset(&zcpr, 0, sizeof(z_stream));
inflateInit(&zcpr);
BYTE __pin * pSource = &source[0];
zcpr.next_in = pSource;
do
{
BYTE *pBuff = new BYTE[BUFFER_SIZE];
buffers.push_back(pBuff);
zcpr.next_out = pBuff;
long all_read_before = zcpr.total_in;
zcpr.avail_in = min(lOrigToDo, BUFFER_SIZE);
zcpr.avail_out = BUFFER_SIZE;
nRes = inflate(&zcpr, Z_SYNC_FLUSH);
if(Z_DATA_ERROR == nRes)
{
throw __gc new ZException(nRes, S"Inflate error");
}
lOrigDone += (zcpr.total_in - all_read_before);
lOrigToDo -= (zcpr.total_in - all_read_before);
} while(Z_OK == nRes);
uLong length = zcpr.total_out;
nRes = inflateEnd(&zcpr);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Inflate end error");
}
System::Byte dest __gc[] = __gc new System::Byte[length];
BYTE __pin * pdata = &dest[0];
for(size_t i=0; i<buffers.size(); ++i)
{
size_t szToCpy = min(BUFFER_SIZE, length-i*BUFFER_SIZE);
memcpy(pdata + i*BUFFER_SIZE, buffers[i], szToCpy);
delete [] buffers[i];
}
return dest;
}
__int64 ZCompressor::CompressStreamCopy(Stream* source, Stream* destination, CompressionLevel level)
{
return CompressStreamCopy(source, destination, level, Convert::ToInt32(source->Length - source->Position));
}
__int64 ZCompressor::CompressStreamCopy(Stream* source, Stream* destination, CompressionLevel level, __int64 length)
{
if(NULL == source)
{
throw __gc new ArgumentNullException(S"source");
}
if(NULL == destination)
{
throw __gc new ArgumentNullException(S"destination");
}
if(length < 0)
{
throw __gc new ArgumentOutOfRangeException(S"length", __box(length),
String::Concat(S"length ", RS::GetResourceString(S"ParamNegative"))
);
}
ZStream* zs = __gc new ZStream(destination, level, CompressionStrategy::Filtered, (_raw ? - MAX_WBITS : MAX_WBITS));
System::Byte buff __gc[] = __gc new System::Byte[BUFFER_SIZE];
while(length > 0)
{
int toRead = static_cast<int>(min(BUFFER_SIZE, length));
int bytesRead = source->Read(buff, 0, toRead);
if(bytesRead == 0)
break;
if(NULL != _checksum)
{
_checksum->Update(buff, 0, bytesRead);
}
zs->Write(buff, 0, bytesRead);
length -= bytesRead;
}
zs->Close();
return zs->CompressedLength;
}
__int64 ZCompressor::UncompressStreamCopy(Stream* source, Stream* destination)
{
return UncompressStreamCopy(source, destination, Convert::ToInt32(source->Length - source->Position));
}
__int64 ZCompressor::UncompressStreamCopy(Stream* source, Stream* destination, __int64 length)
{
if(NULL == source)
{
throw __gc new ArgumentNullException(S"source");
}
if(NULL == destination)
{
throw __gc new ArgumentNullException(S"destination");
}
if(length < 0)
{
throw __gc new ArgumentOutOfRangeException(S"length", __box(length),
String::Concat(S"length ", RS::GetResourceString(S"ParamNegative"))
);
}
ZStream* zs = __gc new ZStream(source, false, (_raw ? - MAX_WBITS : MAX_WBITS));
System::Byte buff __gc[] = __gc new System::Byte[BUFFER_SIZE];
while(length > 0)
{
int bytesProcessed = (int) zs->CompressedLength;
int bytesRead = zs->Read(buff, 0, BUFFER_SIZE);
if(bytesRead == 0)
break;
destination->Write(buff, 0, bytesRead);
if(NULL != _checksum)
{
_checksum->Update(buff, 0, bytesRead);
}
length -= zs->CompressedLength - bytesProcessed;
}
source->Close();
return zs->UncompressedLength;
}