HOME > GZIP 파일의 구조 > 예제 소스 보기

 

 

GZIP 압축 예제 소스 코드

 

 

목차

1.   핵심 사항

2.   gzipfile.h

3.   gzipfilc.cpp

1.   복원

 

 

 

핵심 사항

 

int main( int argc, char *argv[] )

{

        if ( argv[1] == NULL )

               return 0;

 

        //원본 파일의 사이즈를 알아낸다.

        FILE *fp = fopen( argv[1] , "rb" );

        fseek( fp, 0L, SEEK_END );

        int orgsize = ftell( fp );

        fseek( fp, 0L, SEEK_SET );

 

        char buffer[4096];

 

        int tmpsize = orgsize;

        CGZipFile gzipFile;

       

        //압축률을 정한다.

        gzipFile.SetCompressLevel( Z_DEFAULT_COMPRESSION );

        //압축파일을 연다.

        gzipFile.Open( "gzip.gz", "wb" );

 

        char result[ 0x8000 * 2 ];

        //헤더 부분을 생성한다.

        gzipFile.SetHeader( argv[1] );

 

        //압축한다.

        gzipFile.DeflateInit( result, 0x8000 );

        while( (tmpsize - 4096 )> 0 )

        {

               fread( buffer, 4096, 1, fp );

               gzipFile.Write( buffer, 4096 );

               tmpsize -= 4096;

        }

 

        fread( buffer, tmpsize, 1, fp );

        gzipFile.Write( buffer, tmpsize, Z_FINISH );

 

        //Close()함수는 Crc32와 원본 파일의 크기를 기록한다.

        gzipFile.Close( orgsize );

        fclose( fp );

 

        return 1;

}

 

//기본 헤더 정보를 위한 구조체이다.

typedef struct _tagGZIPHEADER

{

        BYTE id[2];

        BYTE cm;

        BYTE flag;

        BYTE mTime[4];

        BYTE xfl;

        BYTE os;

}GZIPHEADER;

 

 

void CGZipFile::SetHeader( const char *_inputfilename )

{

        //ID값은 정해져 있다.

        gzipHeader.id[0] = 0x1f;

        gzipHeader.id[1] =0x8b;

        //CM값도 정해져 있다.

        gzipHeader.cm = 8;

        // flag=8이면 원본 파일의 이름을 기록한다.

        gzipHeader.flag = 8;

 

        //현재 시간을 기록한다.

        time_t mtime;

        time( &mtime );

        memcpy( gzipHeader.mTime, &mtime, 4 );

 

        //XFL값 세팅

        gzipHeader.xfl = 0;

        //파일 시스템 기록

        gzipHeader.os = 0x0b;

 

        //기본헤더 기록

        fseek( fp, 0, SEEK_SET );

        fwrite( &gzipHeader, sizeof( gzipHeader ), 1, fp );

 

        //flag=8이므로 원본 파일의 이름도 기록해야 한다.    

        char buffer[ 128 ];

        char *ptr = (char *)_inputfilename;

        while( *ptr != '\\' && *ptr != '\0' )

        {

               ptr++;

        }

 

        if ( *ptr == '\0' )

        {

               strcpy( buffer, _inputfilename );

        }

        else

        {

               ptr++;

               strcpy( buffer, ptr );

        }

 

        int len = strlen( buffer );

        buffer[ len ] = 0;

 

        fwrite( buffer, len + 1, 1, fp );

}

 

void CGZipFile::Close( int _orgsize )

{

        deflateEnd( &gzipStream );

        //CRC32 정보를 기록한다.

        fwrite( &crc, 4, 1, fp );

        //원본파일의 크기를 기록한다.

        fwrite( &_orgsize, 4, 1, fp );

        fclose(fp);

}

 

 

 

 

// gzipfile.h

#ifndef         __GZIPFILE_H__

#define        __GZIPFILE_H__

 

#include               "zlib.h"

#include               "zconf.h"

 

#ifndef Z_BUFSIZE

#define Z_BUFSIZE (16384)

#endif

 

#ifndef Z_MAXFILENAMEINZIP

#define Z_MAXFILENAMEINZIP (256)

#endif

 

#ifndef DEF_MEM_LEVEL

#if MAX_MEM_LEVEL >= 8

#  define DEF_MEM_LEVEL 8

#else

#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL

#endif

#endif

 

typedef        unsigned char          uchar;

typedef        const uchar                   cuchar;

typedef        unsigned long          ulong;

typedef        uchar                         BYTE;

 

#include               <stdio.h>

 

#define        DEFLATE        0

#define        INFLATE                1

 

typedef struct _tagGZIPHEADER

{

        BYTE id[2];

        BYTE cm;

        BYTE flag;

        BYTE mTime[4];

        BYTE xfl;

        BYTE os;

}GZIPHEADER;

 

class CGZipFile

{

public:

        CGZipFile();

        ~CGZipFile();

 

        inline void SetHeader( const char *_filename );

        int Open( const char *_filename, const char *_mode = "wb" );

        int Write( const char *_data, int _dataSize, int _flush = Z_NO_FLUSH );

        void Close( int _orgsize );

 

        inline void SetCompressLevel( int _compLevel ){ compressLevel = _compLevel; }

        void DeflateInit( char *_resultData, int _resultSize );

       

private:

        GZIPHEADER gzipHeader;

        int fType;

        int compressLevel;

        FILE *fp;     

        char *result;

        int resultSize;

        int crc;

        int orgsize;

 

        z_stream gzipStream;

};

 

#endif         /* gzipfile.h */ 

 

 

 

 

// gzipfile.cpp

////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "gzipfile.h"

#include <string.h>

#include <time.h>

 

CGZipFile::CGZipFile()

{

        fp = NULL;

        fType = DEFLATE;

        compressLevel = Z_DEFAULT_COMPRESSION;

        crc = crc32( 0L, 0L, 0L );

        memset( &gzipStream, 0, sizeof( gzipStream ) );

}

 

CGZipFile::~CGZipFile()

{

        if ( fp )

        {

                fclose( fp );

                fp = NULL;

        }

}

 

void CGZipFile::Close( int _orgsize )

{

        deflateEnd( &gzipStream );

        fwrite( &crc, 4, 1, fp );

        fwrite( &_orgsize, 4, 1, fp );

        fclose(fp);

}

 

int CGZipFile::Open( const char *_filename )

{

        int err;

        gzipStream.zalloc = (alloc_func)0;

        gzipStream.zfree = (free_func)0;

        gzipStream.opaque = (voidpf)0;

 

        fType = DEFLATE;

             //주의!!!!!

             //window bit값이 음수이면 zlib 형식이 아닌 gzip파일 포맷이라는 뜻이다.

        err = deflateInit2( &gzipStream, compressLevel, Z_DEFLATED, -MAX_WBITS,

                DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY );

 

        if ( err != Z_OK )

                return 0;

 

        fp = fopen( _filename, "wb" );

        return (int) fp;

}

 

int CGZipFile::Write( const char *_data, int _dataSize, int _flush )

{

        int err;

        gzipStream.avail_out = (uInt)this->resultSize;

        gzipStream.next_out = (Bytef*)this->result;

        gzipStream.avail_in = (uInt)_dataSize;

        gzipStream.next_in = (Bytef*)_data;

 

        crc = crc32( crc, (const BYTE *)_data, _dataSize );

        err = ::deflate( &gzipStream, _flush );

        if ( err != Z_OK && err != Z_STREAM_END )

                return 0;

 

        int writeSize = gzipStream.total_out;

        if ( writeSize != 0 )

        {

                if ( writeSize > DEFLATE_SIZE )

                        printf("Big Size: %d\n", writeSize );

 

                printf("Size: %d\n", writeSize );

                if ( fwrite( result, writeSize, 1, fp ) == 0 )

                        return Z_ERRNO;

 

                gzipStream.total_out = 0;

        }

 

        if ( err != Z_OK && err != Z_STREAM_END )

                return 0;

 

        return 1;

}

 

void CGZipFile::DeflateInit( char *_resultData , int _resultSize )

{

        result = _resultData;

        resultSize = _resultSize;

}

 

void CGZipFile::SetHeader( const char *_inputfilename )

{

        gzipHeader.id[0] = 0x1f;

        gzipHeader.id[1] =0x8b;

        gzipHeader.cm = 8;

        gzipHeader.flag = 8;

 

        time_t mtime;

        time( &mtime );

        memcpy( gzipHeader.mTime, &mtime, 4 );

 

        gzipHeader.xfl = 0;

        gzipHeader.os = 0x0b;

 

        fseek( fp, 0, SEEK_SET );

        fwrite( &gzipHeader, sizeof( gzipHeader ), 1, fp );

 

        char buffer[ 128 ];

        char *ptr = (char *)_inputfilename;

        while( *ptr != '\\' && *ptr != '\0' )

        {

                ptr++;

        }

 

        if ( *ptr == '\0' )

        {

                strcpy( buffer, _inputfilename );

        }

        else

        {

                ptr++;

                strcpy( buffer, ptr );

        }

 

        int len = strlen( buffer );

        buffer[ len ] = 0;

 

        fwrite( buffer, len + 1, 1, fp );

        

}

 

int main( int argc, char *argv[] )

{

        if ( argv[1] == NULL )

                return 0;

 

        FILE *fp = fopen( argv[1] , "rb" );

        fseek( fp, 0L, SEEK_END );

        int orgsize = ftell( fp );

        fseek( fp, 0L, SEEK_SET );

 

        char buffer[ DEFLATE_SIZE + 1];

 

        int tmpsize = orgsize;

        CGZipFile gzipFile;

        gzipFile.SetCompressLevel( Z_DEFAULT_COMPRESSION );

        gzipFile.Open( "gzip.gz" );

 

        char result[ 0x8000 * 2 ];

        gzipFile.SetHeader( argv[1] );

 

        gzipFile.DeflateInit( result, 0x8000 );

        while( (tmpsize - DEFLATE_SIZE )> 0 )

        {

                fread( buffer, DEFLATE_SIZE, 1, fp );

                gzipFile.Write( buffer, DEFLATE_SIZE );

                tmpsize -= DEFLATE_SIZE;

        }

 

        fread( buffer, tmpsize, 1, fp );

        gzipFile.Write( buffer, tmpsize, Z_FINISH );

 

        gzipFile.Close( orgsize );

        fclose( fp );

 

        return 1;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 

 

 

복원

 

 

void gz_decompress(const char* src_filename)        /* 전개(복원) */

{

        z_stream z;

        unsigned char* inbuf = NULL;

        unsigned char* outbuf = NULL;

        char dest_filename[256]={0,};

        unsigned int count, status;

        unsigned long INBUFSIZE;

        unsigned long OUTBUFSIZE;

       

        //파일 네임 설정

        int strl;

        strl = strlen(src_filename);

        strncpy(dest_filename,src_filename, strl-4);

        printf("dest filename = %s\n\n",dest_filename);

 

        //압축 파일을 읽어들인다.

        FILE* fin = fopen(src_filename, "rb");

        if(fin == NULL)

        {

               printf("%s open failed\n", src_filename);

               exit(1);

        }

 

        FILE* fout = fopen(dest_filename, "wb");

        if(fout == NULL)

        {

               printf("%s open failed\n", dest_filename);

               exit(1);

        }

       

        //압축 파일로부터 헤더를 읽어온다.

        GZIPHEADER header;

        fseek(fin,0,SEEK_SET);

        fread(&header,sizeof(GZIPHEADER),1,fin);

 

        //압축 파일로부터 원래 파일의 이름을 알아온다.

        char filename[1024]="\0";

        int pos=0;

        char _char=(char)fgetc(fin);

        filename[pos]=_char;

        while(_char!='\0')

        {

               pos++;

               _char=(char)fgetc(fin);

               filename[pos]=_char;

        }

        filename[pos]='\0';

 

        fprintf(stdout,"source file name = %s\n\n",filename);

       

        //압축된 파일의 크기를 알아온다.

        fseek(fin,0,SEEK_END);

        unsigned long compressedSize=ftell(fin) - sizeof(GZIPHEADER)

               - ( strlen(filename)+1 ) - sizeof(int)*2;

        fprintf(stdout,"compressed file size = %d\n\n",compressedSize);

       

        //원본 파일의 크기를 알아온다.

unsigned long orgSize=0;

        fseek(fin,0-sizeof(int),SEEK_END);

        fread(&orgSize,sizeof(int),1,fin);

        fprintf(stdout,"original file size = %d\n\n",orgSize);

       

        //압축되어 있는 파일을 메모리로 가져온다.

        fseek(fin,+( sizeof(GZIPHEADER)+(strlen(filename)+1) ),SEEK_SET);

        char *compressedData=new char[compressedSize];

        fread(compressedData,compressedSize,1,fin);

       

        char *orgData=new char[orgSize];

        orgData[0]='\0';

  

       

        //압축을 하기 위한 환경 설정

        INBUFSIZE=compressedSize;

OUTBUFSIZE=orgSize;

inbuf = (unsigned char *)malloc(INBUFSIZE);

outbuf = (unsigned char *)malloc(OUTBUFSIZE);

 

inbuf=(unsigned char*)compressedData;

 

//테스트를 위해 일단 outbuf에 garbage라는 문자열을 넣었다.

strcpy((char*)outbuf, "garbage");

 

        z.zalloc = Z_NULL;

        z.zfree = Z_NULL;

        z.opaque = Z_NULL;

 

        z.next_in  = inbuf;

        z.avail_in = 0;

        z.next_out = outbuf;

 

        //GZIP 형식에서는 window bit값이 MAX_WBITS이다.

int err = inflateInit2(&z,-(MAX_WBITS));

 

        //복원한다.

        while (z.total_out < orgSize && z.total_in < compressedSize) {

               z.avail_in = z.avail_out = 4096; /* force small buffers */

               err = inflate(&z, Z_NO_FLUSH);

 

               if (err == Z_STREAM_END) break;

       

               if (err != Z_OK) {

                       fprintf(stderr, "inflate error: %d\n", err);

                       exit(1);

               }

        }

 

        //복원을 끝낸다.

        err = inflateEnd(&z);

        if (err != Z_OK) {

               fprintf(stderr, "inflateEnd error: %d\n", err);

               exit(1);

        }

}