sample-inflate.c
1
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
37 static int Cio_Open( hCio h, const char *in_path, const char *out_path )
38 {
39
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 = inflateInit( &h->z ) ) != 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 = inflateEnd( &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 = inflate( &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_NEED_DICT:
180 case Z_DATA_ERROR:
181 Cio_ZError( h, h->in_path );
182 return -1;
183 case Z_STREAM_ERROR:
184
185 Cio_ZError( h, NULL );
186 return -1;
187 }
188 }
189
190
191 return Cio_Flush( h );
192 }
193
194
195 static int Cio_Decompress( hCio h )
196 {
197 int ret;
198
199
200 if ( ( ret = Cio_Start( h ) ) )
201 return ret;
202
203
204 ret = Cio_Loop( h );
205
206
207 if ( !ret )
208 Cio_End( h );
209 else
210 ret = Cio_End( h );
211
212 return ret;
213 }
214
215
216 static int Decompress( const char *in_path, const char *out_path )
217 {
218 int ret;
219 Cio io;
220
221
222 if ( ( ret = Cio_Open( &io, in_path, out_path ) ) )
223 return ret;
224
225
226 ret = Cio_Decompress( &io );
227
228
229 Cio_Close( &io );
230
231 return ret;
232 }
233
234 int main( int argc, char *argv[] )
235 {
236 if ( argc != 3 )
237 {
238 fprintf( stderr, "Usage: %s Input Output\n", argv[0] );
239 return -1;
240 }
241
242 return Decompress( argv[1], argv[2] );
243 }