Click here to Skip to main content
15,896,154 members
Articles / Programming Languages / C#

Managed C++ wrapper for ZLib

Rate me:
Please Sign up or sign in to vote.
4.56/5 (14 votes)
3 Mar 2005CPOL9 min read 155.6K   5.7K   46  
.NET wrapper for ZLib, written in MC++
/*
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;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions