[WinAPI] Compress, Decompress 압축 API 사용하기

이번 글에서는 데이터를 압축하는 Windows API를 알아보겠습니다.

Compress를 사용하려면 아래 헤더파일과 라이브러리를 추가해야합니다.

#include "compressapi.h"
#pragma comment ( lib, "Cabinet.lib" )

압축을 위해선 우선 핸들을 만들어야 합니다.

COMPRESSOR_HANDLE hCompressor;
unsigned long ulCompSize = 0;
// 압축 핸들 만들기
if ( CreateCompressor( COMPRESS_ALGORITHM_LZMS , NULL, &hCompressor ) )
{

}

만들어진 핸들을 이용하여 우선 압축 사이즈를 구합니다.

// 압축을 위한 데이터 크기 받기
if ( FALSE == Compress( hCompressor, pOrigin, DATA_SIZE, NULL, 0, &ulCompSize ) )
{
	if ( ulCompSize > 0 )
	{
		
	}
}

사이즈가 정상적으로 반환이 되면 실제 압축을 진행합니다.

unsigned char *pucTemp = new unsigned char[ulCompSize];

// 데이터를 압축 하고, 압축된 데이터의 크기를 다시 받아온다.
if ( TRUE == Compress( hCompressor, pOrigin, DATA_SIZE, pucTemp, ulCompSize, &ulCompSize ) )
{
	pucComp = new unsigned char[ulCompSize];
	memcpy( pucComp, pucTemp, ulCompSize );

	TRACE( _T( "ulCompSize : %d\n" ), ulCompSize );
}

delete pucTemp;

압축이 모두 정상적으로 실행되면 핸들을 닫아줍니다.

CloseCompressor( hCompressor );

위 과정을 진행하면 pucComp 변수에 압축된 데이터가 있습니다.

이제 반대 과정인 압축 해제 함수를 알아보겠습니다.
압축과 비슷하게 우선 핸들부터 만들어야 합니다.

DECOMPRESSOR_HANDLE hDecompressor;
unsigned long ulDecompSize = 0;

// 압축 해제 핸들 얻기
if (CreateDecompressor( COMPRESS_ALGORITHM_LZMS, NULL, &hDecompressor ))
{
	
}

그 다음 압축된 데이터를 해제했을 때 데이터의 크기를 받아오는 작업을 합니다.

// 압축 해제 크기를 얻어온다.
if (FALSE == Decompress( hDecompressor, pucComp, ulCompSize, NULL, 0, &ulDecompSize ))
{
	if (0 < ulDecompSize)
	{
	}
}

데이터 크기를 받아왔다면 그 다음엔 압축 해제를 진행합니다.

unsigned char *pucDecomp = new unsigned char[ulDecompSize];
// 압축 해제한다.
if (TRUE == Decompress( hDecompressor, pucComp, ulCompSize, pucDecomp, ulDecompSize, &ulDecompSize ))
{
	TRACE( _T( "ulDecompSize : %d\n" ), ulDecompSize );
}
delete pucDecomp;

정상적으로 압축 해제를 진행했다면 핸들을 닫아줍니다.

CloseDecompressor( hDecompressor );

전체 코드는 아래와 같습니다.

// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
ULONGLONG ullStart = ::GetTickCount64();

// 압축된 데이터 버퍼
unsigned char *pucComp = NULL;

// 기존 데이터 버퍼
unsigned char *pOrigin = new unsigned char[DATA_SIZE];
for ( int i = 0 ; i < DATA_SIZE ; i++ )
	pOrigin[i] = i % 255;

COMPRESSOR_HANDLE hCompressor;
unsigned long ulCompSize = 0;
// 압축 핸들 만들기
if ( CreateCompressor( COMPRESS_ALGORITHM_LZMS , NULL, &hCompressor ) )
{
	// 압축을 위한 데이터 크기 받기
	if ( FALSE == Compress( hCompressor, pOrigin, DATA_SIZE, NULL, 0, &ulCompSize ) )
	{
		if ( ulCompSize > 0 )
		{
			unsigned char *pucTemp = new unsigned char[ulCompSize];

			// 데이터를 압축 하고, 압축된 데이터의 크기를 다시 받아온다.
			if ( TRUE == Compress( hCompressor, pOrigin, DATA_SIZE, pucTemp, ulCompSize, &ulCompSize ) )
			{
				pucComp = new unsigned char[ulCompSize];
				memcpy( pucComp, pucTemp, ulCompSize );

				TRACE( _T( "ulCompSize : %d\n" ), ulCompSize );
			}

			delete pucTemp;
		}
	}

	CloseCompressor( hCompressor );
}

delete pOrigin;
pOrigin = NULL;

ULONGLONG ullEnd = ::GetTickCount64();
TRACE( _T( "Comp Time Gap : %d\n" ), ullEnd - ullStart );

ullStart = ::GetTickCount64();	
if (NULL != pucComp)
{
	DECOMPRESSOR_HANDLE hDecompressor;
	unsigned long ulDecompSize = 0;

	// 압축 해제 핸들 얻기
	if (CreateDecompressor( COMPRESS_ALGORITHM_LZMS, NULL, &hDecompressor ))
	{
		// 압축 해제 크기를 얻어온다.
		if (FALSE == Decompress( hDecompressor, pucComp, ulCompSize, NULL, 0, &ulDecompSize ))
		{
			if (0 < ulDecompSize)
			{
				unsigned char *pucDecomp = new unsigned char[ulDecompSize];
				// 압축 해제한다.
				if (TRUE == Decompress( hDecompressor, pucComp, ulCompSize, pucDecomp, ulDecompSize, &ulDecompSize ))
				{
					TRACE( _T( "ulDecompSize : %d\n" ), ulDecompSize );
				}
				delete pucDecomp;
			}
		}
		CloseDecompressor( hDecompressor );
	}
}
ullEnd = ::GetTickCount64();

TRACE( _T( "Decomp Time Gap : %d\n" ), ullEnd - ullStart );

if (NULL != pucComp)
	delete pucComp;

위 소스를 보시면 16,384 크기가 44까지 줄은 것을 알 수 있습니다.

압축 옵션은 아래와 같이 4개가 있는데 각각의 옵션은 압축률과 압축시간과 관련된 옵션입니다.

COMPRESS_ALGORITHM_MSZIP	// 압축률 낮고, 시간 빠름
COMPRESS_ALGORITHM_XPRESS
COMPRESS_ALGORITHM_XPRESS_HUFF
COMPRESS_ALGORITHM_LZMS		// 압축률 높고, 시간 느림