sample-deflate.c
  1  // zlib による圧縮のサンプル
  2  #include    <stdio.h>
  3  #include    <string.h>
  4  #include    <zlib.h>
  5  
  6  
  7  // バッファサイズ
  8  #define     IN_BUFSIZE      4096    // 入力用
  9  #define     OUT_BUFSIZE     4096    // 出力用
 10  
 11  
 12  // 入出力用の構造体
 13  typedef     struct Cio
 14  {
 15      const char  *in_path;   // 入力ファイル名
 16      const char  *out_path;  // 出力ファイル名
 17      FILE        *in;        // 入力ファイル
 18      FILE        *out;       // 出力ファイル
 19  
 20      z_stream    z;  // 圧縮用の構造体
 21  
 22      char    in_buf[ IN_BUFSIZE ];       // 入力用のバッファ
 23      char    out_buf[ OUT_BUFSIZE ];     // 出力用バッファ
 24  }   Cio, *hCio;
 25  
 26  
 27  // エラーメッセージを出力する
 28  static  void    Cio_ZError( hCio h, const char *msg )
 29  {
 30      if ( msg != NULL )
 31          fprintf( stderr, "%s: ", msg );
 32      fprintf( stderr, "%s\n", h->z.msg );
 33  }
 34  
 35  // 入出力ファイルを開く
 36  // 失敗した場合,in と out を NULL にして -1 を返す
 37  static  int     Cio_Open( hCio h, const char *in_path, const char *out_path )
 38  {
 39      // 0 で初期化する
 40      memset( h, 0, sizeof( *h ) );
 41  
 42      // パスを保存する
 43      h->in_path = in_path;
 44      h->out_path = out_path;
 45  
 46      if ( ( h->in = fopen( in_path, "rb" ) ) == NULL )
 47      {
 48          // 入力ファイルを開くのに失敗
 49          perror( in_path );
 50          h->out = NULL;
 51          return  -1;
 52      }
 53      else if ( ( h->out = fopen( out_path, "wb" ) ) == NULL )
 54      {
 55          // 出力ファイルを開くのに失敗
 56          perror( out_path );
 57          h->in = NULL;
 58          return  -1;
 59      }
 60  
 61      return  0;
 62  }
 63  
 64  // 入出力ファイルを閉じる
 65  static  void    Cio_Close( hCio h )
 66  {
 67      if ( h->in != NULL )
 68          fclose( h->in );
 69      if ( h->out != NULL )
 70          fclose( h->out );
 71  }
 72  
 73  // 入力バッファを埋める
 74  static  int     Cio_Fill( hCio h )
 75  {
 76      // 入力ファイルからの読み込み
 77      h->z.next_in = h->in_buf;
 78      h->z.avail_in = fread( h->in_buf, 1, IN_BUFSIZE, h->in );
 79      if ( h->z.avail_in <= 0 )
 80      {
 81          if ( ferror( h->in ) )
 82          {
 83              // 入力エラー
 84              perror( h->in_path );
 85              return  -1;
 86          }
 87          // 入力ファイルの終端
 88          return  0;
 89      }
 90  
 91      return  0;
 92  }
 93  
 94  // 出力バッファを空にする
 95  static  int     Cio_Flush( hCio h )
 96  {
 97      // 出力ファイルへの書き込み
 98      if ( fwrite( h->out_buf, OUT_BUFSIZE - h->z.avail_out, 1, h->out ) != 1 )
 99      {
100          // 出力エラー
101          perror( h->out_path );
102          return  -1;
103      }
104      h->z.next_out = h->out_buf;
105      h->z.avail_out = OUT_BUFSIZE;
106  
107      return  0;
108  }
109  
110  // 圧縮の準備をする
111  static  int     Cio_Start( hCio h )
112  {
113      int     ret;
114  
115      // メモリ確保はライブラリに任せる
116      h->z.zalloc = Z_NULL;
117      h->z.zfree = Z_NULL;
118      h->z.opaque = Z_NULL;
119  
120      // 圧縮用の構造体を初期化する
121      if ( ( ret = deflateInit( &h->z, Z_DEFAULT_COMPRESSION ) ) != Z_OK )
122      {
123          Cio_ZError( h, NULL );
124          return  -1;
125      }
126  
127      // 入出力を初期化する
128      h->z.next_in = h->in_buf;
129      h->z.avail_in = 0;
130      h->z.next_out = h->out_buf;
131      h->z.avail_out = OUT_BUFSIZE;
132  
133      return  0;
134  }
135  
136  // 圧縮の終了処理をする
137  static  int     Cio_End( hCio h )
138  {
139      int     ret;
140  
141      // 圧縮用の構造体を破棄する
142      if ( ( ret = deflateEnd( &h->z ) ) != Z_OK )
143      {
144          Cio_ZError( h, NULL );
145          return  -1;
146      }
147  
148      return  0;
149  }
150  
151  // 圧縮のためのループ
152  static  int     Cio_Loop( hCio h )
153  {
154      int     ret, flush = Z_NO_FLUSH;
155  
156      while ( ( ret = deflate( &h->z, flush ) ) != Z_STREAM_END )
157      {
158          switch ( ret )
159          {
160          case    Z_OK:           // 問題なし
161          case    Z_BUF_ERROR:    // 入力バッファが空か出力バッファが満杯
162              // 入力バッファを埋める
163              if ( !h->z.avail_in )
164              {
165                  if ( ( ret = Cio_Fill( h ) ) )
166                      return  -1;
167  
168                  // 入力ファイルの終端に達したら動作を変更する
169                  if ( !h->z.avail_in )
170                      flush = Z_FINISH;
171              }
172              // 出力バッファを空にする
173              if ( !h->z.avail_out )
174              {
175                  if ( ( ret = Cio_Flush( h ) ) )
176                      return  -1;
177              }
178              break;
179          case    Z_STREAM_ERROR:
180              // 入出力が想定外のエラー(例えば,next_in, next_out が NULL)
181              Cio_ZError( h, NULL );
182              return  -1;
183          }
184      }
185  
186      // 出力バッファの残りを出力ファイルに書き出す
187      return  Cio_Flush( h );
188  }
189  
190  // 圧縮する
191  static  int     Cio_Compress( hCio h )
192  {
193      int     ret;
194  
195      // 圧縮の準備
196      if ( ( ret = Cio_Start( h ) ) )
197          return  ret;
198  
199      // 圧縮のループ
200      ret = Cio_Loop( h );
201  
202      // 圧縮の後片付け
203      if ( !ret )
204          Cio_End( h );
205      else
206          ret = Cio_End( h );
207  
208      return  ret;
209  }
210  
211  // in_path を圧縮して out_path に出力する
212  static  int     Compress( const char *in_path, const char *out_path )
213  {
214      int     ret;
215      Cio     io;
216  
217      // 入出力ファイルを開く
218      if ( ( ret = Cio_Open( &io, in_path, out_path ) ) )
219          return  ret;
220  
221      // 圧縮する
222      ret = Cio_Compress( &io );
223  
224      // 入出力ファイルを閉じる
225      Cio_Close( &io );
226  
227      return  ret;
228  }
229  
230  int     main( int argc, char *argv[] )
231  {
232      if ( argc != 3 )
233      {
234          fprintf( stderr, "Usage: %s Input Output\n", argv[0] );
235          return  -1;
236      }
237  
238      return  Compress( argv[1], argv[2] );
239  }