/*
DevelopDotNet
http://www.developdotnet.com
File Created by: Alberto Ferrazzoli
Date: 20/05/2004
Class Description:
ZStream
Notes:
Revision Log - Please mark significant changes in source code in the following format:
Date - Time - Reviewer - Comments
10/07/2004 Alberto Ferrazzoli ZStream header presence selection for compatibility with
raw zip file format.
15/07/2004 Alberto Ferrazzoli Bug Fix on ZFlush() and ZFinish()
23/07/2004 Alberto Ferrazzoli Bug Fix ZLibDeflateCleanUp()
25/07/2004 Alberto Ferrazzoli Support for read only ZStream.
*/
#include "stdafx.h"
#include "RS.h"
#include "IChecksum.h"
#include "ZStream.h"
#using <mscorlib.dll>
using namespace DevelopDotNet::Compression;
ZStream::ZStream(Stream *stream)
{
_canWrite = false;
_canRead = true;
Initialize(stream, CompressionLevel::Normal, CompressionStrategy::DefaultStrategy, MAX_WBITS);
}
ZStream::ZStream(Stream *stream, bool write)
{
_canWrite = write;
_canRead = !write;
Initialize(stream, CompressionLevel::Normal, CompressionStrategy::DefaultStrategy, MAX_WBITS);
}
ZStream::ZStream(Stream *stream, CompressionLevel level)
{
_canWrite = true;
_canRead = false;
Initialize(stream, level, CompressionStrategy::DefaultStrategy, MAX_WBITS);
}
ZStream::ZStream(Stream *stream, CompressionLevel level, CompressionStrategy strategy)
{
_canWrite = true;
_canRead = false;
Initialize(stream, level, strategy, MAX_WBITS);
}
ZStream::ZStream(Stream *stream, bool write, int bits)
{
_canWrite = write;
_canRead = !write;
Initialize(stream, CompressionLevel::Normal, CompressionStrategy::DefaultStrategy, bits);
}
ZStream::ZStream(Stream *stream, bool write, int bits, IChecksum* checksum)
{
_canWrite = write;
_canRead = !write;
_checksum = checksum;
Initialize(stream, CompressionLevel::Normal, CompressionStrategy::DefaultStrategy, bits);
}
ZStream::ZStream(Stream *stream, CompressionLevel level, CompressionStrategy strategy, int bits)
{
_canWrite = true;
_canRead = false;
Initialize(stream, level, strategy, bits);
}
ZStream::ZStream(Stream *stream, CompressionLevel level, CompressionStrategy strategy, int bits, IChecksum* checksum)
{
_canWrite = true;
_canRead = false;
_checksum = checksum;
Initialize(stream, level, strategy, bits);
}
void ZStream::Initialize(Stream *stream, CompressionLevel level, CompressionStrategy strategy, int windowBits)
{
_disposed = false;
_ownerBaseStream = false;
m_zbufLen = 0;
m_zcurPos = 0;
_canSeek = false;
_stream = stream;
m_zbuffer = __gc new unsigned char __gc[BUFFER_SIZE];
if (_canRead)
{
if (! _stream->CanRead)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoRead"));
}
ZLibInflateInit(windowBits);
}
else
{
if (! _stream->CanWrite)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoWrite"));
}
if ( Z_OK == ZLibDeflateInit(windowBits))
{
ZLibParam(level, strategy);
}
}
}
int ZStream::ZLibInflateInit(int windowBits)
{
z_stream __pin * zstmp = &m_zstm;
int nRes = inflateInit2(zstmp, windowBits);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Inflate init error");
}
return nRes;
}
int ZStream::ZLibInflateCleanUp()
{
z_stream __pin * zstmp = &m_zstm;
int nRes = inflateEnd(zstmp);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Inflate cleanup error");
}
return nRes;
}
int ZStream::ZLibDeflateInit(int windowBits)
{
z_stream __pin * zstmp = &m_zstm;
int nRes = deflateInit2(zstmp, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Deflate init error");
}
return nRes;
}
int ZStream::ZLibDeflateCleanUp()
{
int nRes;
BYTE __pin *zbuff = &m_zbuffer[0];
if (m_zbufLen > 0)
{
_stream->Write(m_zbuffer, 0, m_zbufLen);
m_zbufLen = 0;
}
z_stream __pin * zstmp = &m_zstm;
do
{
int nDone = m_zstm.total_out;
m_zstm.next_out = (Bytef*) &zbuff[m_zbufLen];
m_zstm.avail_out = (uInt) (BUFFER_SIZE - m_zbufLen);
nRes = deflate(zstmp, Z_FINISH);
if(nRes < 0)
break;
nDone = m_zstm.total_out - nDone;
_stream->Write(m_zbuffer, 0, nDone);
} while(Z_OK == nRes);
if(Z_STREAM_END == nRes)
nRes = deflateEnd(zstmp);
if (Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Deflate cleanup error");
}
return nRes;
}
bool ZStream::ZLibParam(CompressionLevel level, CompressionStrategy strategy)
{
bool bRes = false;
z_stream __pin * zstmp = &m_zstm;
int nRes = deflateParams(zstmp, level, strategy);
if (Z_OK == nRes)
{
_compressionlevel = level;
_compressionstrategy = strategy;
bRes = true;
}
return bRes;
}
__int64 ZStream::get_Length()
{
return _stream->Length;
}
__int64 ZStream::get_Position()
{
return _stream->Position;
}
void ZStream::set_Position(__int64 /* pos */)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoSeek"));
}
void ZStream::set_Level(CompressionLevel value)
{
if (!_canWrite)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoWrite"));
}
ZLibParam(value, _compressionstrategy);
}
void ZStream::set_Strategy(CompressionStrategy value)
{
if (!_canWrite)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoWrite"));
}
ZLibParam(_compressionlevel, value);
}
__int64 ZStream::get_CompressedLength()
{
return _canWrite ? m_zstm.total_out : m_zstm.total_in;
}
__int64 ZStream::get_UncompressedLength()
{
return _canWrite ? m_zstm.total_in : m_zstm.total_out;
}
CompressedDataType ZStream::get_DataType()
{
CompressedDataType datatype = CompressedDataType::Unknown;
switch(m_zstm.data_type)
{
case Z_BINARY:
datatype = CompressedDataType::Binary;
break;
case Z_ASCII:
datatype = CompressedDataType::Ascii;
break;
case Z_UNKNOWN:
default:
break;
}
return datatype;
}
String* ZStream::get_ZLibVersion()
{
const char * version = zlibVersion();
return __gc new String(version);
}
int ZStream::get_Checksum()
{
int checksum = _checksum != NULL ? _checksum->Checksum : m_zstm.adler;
return checksum;
}
int ZStream::Read([In, Out] unsigned char buffer __gc[], int offset, int count)
{
if (NULL == buffer)
throw __gc new ArgumentNullException(S"buffer", RS::GetResourceString(S"BufferNotNull"));
if (offset < 0)
throw __gc new ArgumentOutOfRangeException(S"offset", __box(offset),
String::Concat(S"offset ", RS::GetResourceString(S"ParamNegative"))
);
if (count < 0)
throw __gc new ArgumentOutOfRangeException(S"count", __box(count),
String::Concat(S"count ", RS::GetResourceString(S"ParamNegative"))
);
if (buffer->Length - offset < count)
throw __gc new ArgumentException(RS::GetResourceString(S"CountExceed"));
if (!_canRead)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoRead"));
}
int nRead = 0;
int nRes = Z_ERRNO;
try
{
nRes = ZRead(&buffer[offset], count, &nRead);
if(NULL != _checksum)
{
_checksum->Update(buffer, offset, count);
}
}
catch(IOException* e)
{
throw __gc new ZException(nRes, S"Inflate error", e);
}
if(nRes < 0)
{
throw __gc new ZException(nRes, S"Inflate error");
}
return nRead;
}
int ZStream::ZRead(unsigned char __gc * buffer, int cb, int *pcbRead)
{
BYTE __pin *zbuff = &m_zbuffer[0];
unsigned char __pin * pv = buffer;
m_zstm.next_out = pv;
m_zstm.avail_out = (uInt) cb;
if (m_zcurPos == m_zbufLen)
{
m_zbufLen = _stream->Read(m_zbuffer, 0, BUFFER_SIZE);
m_zcurPos = 0;
}
int nRes = Z_OK;
do
{
m_zstm.next_in = (Bytef *) &zbuff[m_zcurPos];
m_zstm.avail_in = (uInt) (m_zbufLen - m_zcurPos);
if (m_zstm.avail_in == 0)
{
break;
}
z_stream __pin * zstmp = &m_zstm;
nRes = inflate(zstmp, Z_SYNC_FLUSH);
if (nRes != Z_OK)
break;
if (m_zstm.avail_out == 0)
{
m_zcurPos = m_zstm.next_in - (Bytef*) &zbuff[0];
break;
}
m_zbufLen = _stream->Read(m_zbuffer, 0, BUFFER_SIZE);
m_zcurPos = 0;
} while (m_zstm.avail_out > 0);
if (pcbRead)
*pcbRead = cb - m_zstm.avail_out;
return nRes;
}
void ZStream::Write(unsigned char buffer __gc[], int offset, int count)
{
if (NULL == buffer)
throw new ArgumentNullException(S"buffer", RS::GetResourceString(S"BufferNotNull"));
if (offset < 0)
throw __gc new ArgumentOutOfRangeException(S"offset", __box(offset),
String::Concat(S"offset ", RS::GetResourceString(S"ParamNegative"))
);
if (count < 0)
throw __gc new ArgumentOutOfRangeException(S"count", __box(count),
String::Concat(S"count ", RS::GetResourceString(S"ParamNegative"))
);
if (buffer->Length - offset < count)
throw new ArgumentException(RS::GetResourceString(S"CountExceed"));
if (!_canWrite)
{
throw __gc new NotSupportedException(RS::GetResourceString(S"NoWrite"));
}
int nRes = Z_ERRNO;
try
{
if(NULL != _checksum)
{
_checksum->Update(buffer, offset, count);
}
nRes = ZWrite(&buffer[offset], count);
}
catch(IOException* e)
{
throw __gc new ZException(nRes, S"Deflate error", e);
}
if(nRes < 0)
{
throw __gc new ZException(nRes, S"Deflate error");
}
}
int ZStream::ZWrite(unsigned char __gc * buffer, int cb)
{
BYTE __pin *zbuff = &m_zbuffer[0];
// Prepare input buffer
unsigned char __pin * pv = buffer;
m_zstm.next_in = pv;
m_zstm.avail_in = (uInt) cb;
if(BUFFER_SIZE == m_zbufLen)
{
_stream->Write(m_zbuffer, 0, m_zbufLen);
m_zbufLen = 0;
}
int nRes = Z_OK;
do
{
int nDone = m_zstm.total_out;
m_zstm.next_out = (Bytef*) &zbuff[m_zbufLen];
m_zstm.avail_out = (uInt) (BUFFER_SIZE - m_zbufLen);
z_stream __pin * zstmp = &m_zstm;
nRes = deflate(zstmp, Z_NO_FLUSH);
if (nRes != Z_OK)
break;
nDone = m_zstm.total_out - nDone;
if(m_zstm.avail_in == 0)
{
m_zbufLen += nDone;
break;
}
_stream->Write(m_zbuffer, 0, nDone);
m_zbufLen = 0;
} while (m_zstm.avail_in > 0);
return nRes;
}
__int64 ZStream::Seek(__int64 offset, System::IO::SeekOrigin origin)
{
if(_canRead)
{
return _stream->Seek(offset, origin);
}
throw new NotSupportedException(RS::GetResourceString(S"NoSeek"));
}
void ZStream::Flush()
{
if(_canWrite)
{
int nRes = ZFlush();
if(Z_OK != nRes)
{
throw __gc new ZException(nRes, S"Flush error");
}
}
_stream->Flush();
}
int ZStream::ZFlush()
{
int nRes = Z_OK;
BYTE __pin *zbuff = &m_zbuffer[0];
if (m_zbufLen > 0)
{
_stream->Write(m_zbuffer, 0, m_zbufLen);
m_zbufLen = 0;
}
do
{
int nDoneUntillNow = m_zstm.total_out;
m_zstm.next_out = (Bytef*) &zbuff[m_zbufLen];
m_zstm.avail_out = (uInt) (BUFFER_SIZE - m_zbufLen);
z_stream __pin * zstmp = &m_zstm;
nRes = deflate(zstmp, Z_FULL_FLUSH);
if (nRes != Z_OK)
break;
m_zbufLen += m_zstm.total_out - nDoneUntillNow;
_stream->Write(m_zbuffer, 0, m_zbufLen);
m_zbufLen = 0;
} while(m_zstm.avail_out == 0);
return nRes;
}
int ZStream::ZFinish()
{
return (_canRead ? ZLibInflateCleanUp() : ZLibDeflateCleanUp());
}
void ZStream::SetLength(__int64 value)
{
_stream->SetLength(value);
}
void ZStream::Close()
{
Dispose(true);
}