]> git.lizzy.rs Git - zlib.git/blob - gzwrite.c
zlib 1.2.3.5
[zlib.git] / gzwrite.c
1 /* gzwrite.c -- zlib functions for writing gzip files
2  * Copyright (C) 2004, 2005, 2010 Mark Adler
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  */
5
6 #ifndef OLD_GZIO
7
8 #include "gzguts.h"
9
10 /* Local functions */
11 local int gz_init OF((gz_statep));
12 local int gz_comp OF((gz_statep, int));
13 local int gz_zero OF((gz_statep, z_off_t));
14
15 /* Initialize state for writing a gzip file.  Mark initialization by setting
16    state->size to non-zero.  Return -1 on failure or 0 on success. */
17 local int gz_init(state)
18     gz_statep state;
19 {
20     int ret;
21     z_streamp strm = &(state->strm);
22
23     /* check version of zlib -- need 1.2.1 or later for gzip deflate() */
24 #ifdef ZLIB_VERNUM
25     if (ZLIB_VERNUM < 0x1210)
26 #endif
27     {
28         gz_error(state, Z_VERSION_ERROR, "need zlib 1.2.1 or later");
29         return -1;
30     }
31
32     /* allocate input and output buffers */
33     state->in = malloc(state->want);
34     state->out = malloc(state->want);
35     if (state->in == NULL || state->out == NULL) {
36         if (state->out != NULL)
37             free(state->out);
38         if (state->in != NULL)
39             free(state->in);
40         gz_error(state, Z_MEM_ERROR, "out of memory");
41         return -1;
42     }
43
44     /* allocate deflate memory, set up for gzip compression */
45     strm->zalloc = Z_NULL;
46     strm->zfree = Z_NULL;
47     strm->opaque = Z_NULL;
48     ret = deflateInit2(strm, state->level, Z_DEFLATED,
49                        15 + 16, 8, state->strategy);
50     if (ret != Z_OK) {
51         free(state->in);
52         gz_error(state, Z_MEM_ERROR, "out of memory");
53         return -1;
54     }
55
56     /* mark state as initialized */
57     state->size = state->want;
58
59     /* initialize write buffer */
60     strm->avail_out = state->size;
61     strm->next_out = state->out;
62     state->next = strm->next_out;
63     return 0;
64 }
65
66 /* Compress whatever is at avail_in and next_in and write to the output file.
67    Return -1 if there is an error writing to the output file, otherwise 0.
68    flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
69    then the deflate() state is reset to start a new gzip stream. */
70 local int gz_comp(state, flush)
71     gz_statep state;
72     int flush;
73 {
74     int ret;
75     unsigned have;
76     z_streamp strm = &(state->strm);
77
78     /* allocate memory if this is the first time through */
79     if (state->size == 0 && gz_init(state) == -1)
80         return -1;
81
82     /* run deflate() on provided input until it produces no more output */
83     ret = Z_OK;
84     do {
85         /* write out current buffer contents if full, or if flushing, but if
86            doing Z_FINISH then don't write until we get to Z_STREAM_END */
87         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
88             (flush != Z_FINISH || ret == Z_STREAM_END))) {
89             have = strm->next_out - state->next;
90             if (have && write(state->fd, state->next, have) != have) {
91                 gz_error(state, Z_ERRNO, zstrerror());
92                 return -1;
93             }
94             if (strm->avail_out == 0) {
95                 strm->avail_out = state->size;
96                 strm->next_out = state->out;
97             }
98             state->next = strm->next_out;
99         }
100
101         /* compress */
102         have = strm->avail_out;
103         ret = deflate(strm, flush);
104         if (ret == Z_STREAM_ERROR) {
105             gz_error(state, Z_STREAM_ERROR,
106                       "internal error: deflate stream corrupt");
107             return -1;
108         }
109         have -= strm->avail_out;
110     } while (have);
111
112     /* if that completed a deflate stream, allow another to start */
113     if (flush == Z_FINISH)
114         deflateReset(strm);
115
116     /* all done, no errors */
117     return 0;
118 }
119
120 /* Compress len zeros to output.  Return -1 on error, 0 on success. */
121 local int gz_zero(state, len)
122     gz_statep state;
123     z_off_t len;
124 {
125     int first;
126     unsigned n;
127     z_streamp strm = &(state->strm);
128
129     /* consume whatever's left in the input buffer */
130     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
131         return -1;
132
133     /* compress len zeros */
134     first = 1;
135     while (len) {
136         n = len < state->size ? (unsigned)len : state->size;
137         if (first) {
138             memset(state->in, 0, n);
139             first = 0;
140         }
141         strm->avail_in = n;
142         strm->next_in = state->in;
143         state->pos += n;
144         if (gz_comp(state, Z_NO_FLUSH) == -1)
145             return -1;
146         len -= n;
147     }
148     return 0;
149 }
150
151 /* -- see zlib.h -- */
152 int ZEXPORT gzwrite(file, buf, len)
153     gzFile file;
154     voidpc buf;
155     unsigned len;
156 {
157     unsigned put = len;
158     unsigned n;
159     gz_statep state;
160     z_streamp strm;
161
162     /* get internal structure */
163     if (file == NULL)
164         return -1;
165     state = (gz_statep)file;
166     strm = &(state->strm);
167
168     /* check that we're writing and that there's no error */
169     if (state->mode != GZ_WRITE || state->err != Z_OK)
170         return -1;
171
172     /* allocate memory if this is the first time through */
173     if (state->size == 0 && gz_init(state) == -1)
174         return -1;
175
176     /* check for seek request */
177     if (state->seek) {
178         state->seek = 0;
179         if (gz_zero(state, state->skip) == -1)
180             return -1;
181     }
182
183     /* for small len, copy to input buffer, otherwise compress directly */
184     if (len < state->size) {
185         /* copy to input buffer, compress when full */
186         while (len) {
187             if (strm->avail_in == 0)
188                 strm->next_in = state->in;
189             n = state->size - strm->avail_in;
190             if (n > len)
191                 n = len;
192             memcpy(strm->next_in + strm->avail_in, buf, n);
193             strm->avail_in += n;
194             state->pos += n;
195             buf += n;
196             len -= n;
197             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
198                 return -1;
199         }
200     }
201     else {
202         /* consume whatever's left in the input buffer */
203         if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
204             return -1;
205
206         /* directly compress user buffer to file */
207         strm->avail_in = len;
208         strm->next_in = (voidp)buf;
209         state->pos += len;
210         if (gz_comp(state, Z_NO_FLUSH) == -1)
211             return -1;
212     }
213
214     /* input was all buffered or compressed */
215     return (int)put;
216 }
217
218 /* -- see zlib.h -- */
219 int ZEXPORT gzputc(file, c)
220     gzFile file;
221     int c;
222 {
223     unsigned char buf[1];
224     gz_statep state;
225     z_streamp strm;
226
227     /* get internal structure */
228     if (file == NULL)
229         return -1;
230     state = (gz_statep)file;
231     strm = &(state->strm);
232
233     /* check that we're writing and that there's no error */
234     if (state->mode != GZ_WRITE || state->err != Z_OK)
235         return -1;
236
237     /* check for seek request */
238     if (state->seek) {
239         state->seek = 0;
240         if (gz_zero(state, state->skip) == -1)
241             return -1;
242     }
243
244     /* try writing to input buffer for speed (state->size == 0 if buffer not
245        initialized) */
246     if (strm->avail_in < state->size) {
247         if (strm->avail_in == 0)
248             strm->next_in = state->in;
249         strm->next_in[strm->avail_in++] = c;
250         state->pos++;
251         return c;
252     }
253
254     /* no room in buffer or not initialized, use gz_write() */
255     buf[0] = c;
256     if (gzwrite(file, buf, 1) != 1)
257         return -1;
258     return c;
259 }
260
261 /* -- see zlib.h -- */
262 int ZEXPORT gzputs(file, str)
263     gzFile file;
264     const char *str;
265 {
266     /* write string */
267     return gzwrite(file, str, strlen(str));
268 }
269
270 #ifdef STDC
271 #include <stdarg.h>
272
273 /* -- see zlib.h -- */
274 int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
275 {
276     int size, len;
277     gz_statep state;
278     z_streamp strm;
279     va_list va;
280
281     /* get internal structure */
282     if (file == NULL)
283         return -1;
284     state = (gz_statep)file;
285     strm = &(state->strm);
286
287     /* check that we're writing and that there's no error */
288     if (state->mode != GZ_WRITE || state->err != Z_OK)
289         return 0;
290
291     /* make sure we have some buffer space */
292     if (state->size == 0 && gz_init(state) == -1)
293         return 0;
294
295     /* check for seek request */
296     if (state->seek) {
297         state->seek = 0;
298         if (gz_zero(state, state->skip) == -1)
299             return 0;
300     }
301
302     /* consume whatever's left in the input buffer */
303     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
304         return 0;
305
306     /* do the printf() into the input buffer, put length in len */
307     size = (int)(state->size);
308     state->in[size - 1] = 0;
309     va_start(va, format);
310 #ifdef NO_vsnprintf
311 #  ifdef HAS_vsprintf_void
312     (void)vsprintf(state->in, format, va);
313     va_end(va);
314     for (len = 0; len < state->in; len++)
315         if (state->in[len] == 0) break;
316 #  else
317     len = vsprintf(state->in, format, va);
318     va_end(va);
319 #  endif
320 #else
321 #  ifdef HAS_vsnprintf_void
322     (void)vsnprintf(state->in, size, format, va);
323     va_end(va);
324     len = strlen(state->in);
325 #  else
326     len = vsnprintf((char *)(state->in), size, format, va);
327     va_end(va);
328 #  endif
329 #endif
330
331     /* check that printf() results fit in buffer */
332     if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
333         return 0;
334
335     /* write out result of printf() */
336     strm->avail_in = (unsigned)len;
337     strm->next_in = state->in;
338     state->pos += len;
339     if (gz_comp(state, Z_NO_FLUSH) == -1)
340         return 0;
341     return len;
342 }
343
344 #else /* !STDC */
345
346 /* -- see zlib.h -- */
347 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
348                        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
349     gzFile file;
350     const char *format;
351     int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
352         a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
353 {
354     int size, len;
355     gz_statep state;
356     z_streamp strm;
357
358     /* get internal structure */
359     if (file == NULL)
360         return -1;
361     state = (gz_statep)file;
362     strm = &(state->strm);
363
364     /* check that we're writing and that there's no error */
365     if (state->mode != GZ_WRITE || state->err != Z_OK)
366         return 0;
367
368     /* make sure we have some buffer space */
369     if (state->size == 0 && gz_init(state) == -1)
370         return 0;
371
372     /* check for seek request */
373     if (state->seek) {
374         state->seek = 0;
375         if (gz_zero(state, state->skip) == -1)
376             return 0;
377     }
378
379     /* consume whatever's left in the input buffer */
380     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
381         return 0;
382
383     /* do the printf() into the input buffer, put length in len */
384     size = (int)(state->size);
385     state->in[size - 1] = 0;
386 #ifdef NO_snprintf
387 #  ifdef HAS_sprintf_void
388     sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
389             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
390     for (len = 0; len < size; len++)
391         if (state->in[len] == 0) break;
392 #  else
393     len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
394                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
395 #  endif
396 #else
397 #  ifdef HAS_snprintf_void
398     snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
399              a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
400     len = strlen(state->in);
401 #  else
402     len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
403                  a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
404 #  endif
405 #endif
406
407     /* check that printf() results fit in buffer */
408     if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
409         return 0;
410
411     /* write out result of printf() */
412     strm->avail_in = (unsigned)len;
413     strm->next_in = state->in;
414     state->pos += len;
415     if (gz_comp(state, Z_NO_FLUSH) == -1)
416         return 0;
417     return len;
418 }
419
420 #endif
421
422 /* -- see zlib.h -- */
423 int ZEXPORT gzflush(file, flush)
424     gzFile file;
425     int flush;
426 {
427     gz_statep state;
428
429     /* get internal structure */
430     if (file == NULL)
431         return -1;
432     state = (gz_statep)file;
433
434     /* check that we're writing and that there's no error */
435     if (state->mode != GZ_WRITE|| state->err != Z_OK)
436
437     /* check flush parameter */
438     if (flush < 0 || flush > Z_FINISH)
439         return Z_STREAM_ERROR;
440
441     /* check for seek request */
442     if (state->seek) {
443         state->seek = 0;
444         if (gz_zero(state, state->skip) == -1)
445             return -1;
446     }
447
448     /* compress remaining data with requested flush */
449     gz_comp(state, flush);
450     return state->err;
451 }
452
453 /* -- see zlib.h -- */
454 int ZEXPORT gzsetparams(file, level, strategy)
455     gzFile file;
456     int level;
457     int strategy;
458 {
459     gz_statep state;
460     z_streamp strm;
461
462     /* get internal structure */
463     if (file == NULL)
464         return Z_STREAM_ERROR;
465     state = (gz_statep)file;
466     strm = &(state->strm);
467
468     /* check that we're writing and that there's no error */
469     if (state->mode != GZ_WRITE || state->err != Z_OK)
470         return Z_STREAM_ERROR;
471
472     /* if no change is requested, then do nothing */
473     if (level == state->level && strategy == state->strategy)
474         return Z_OK;
475
476     /* check for seek request */
477     if (state->seek) {
478         state->seek = 0;
479         if (gz_zero(state, state->skip) == -1)
480             return -1;
481     }
482
483     /* change compression parameters for subsequent input */
484     if (state->size) {
485         /* flush previous input with previous parameters before changing */
486         if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
487             return state->err;
488         deflateParams(strm, level, strategy);
489     }
490     state->level = level;
491     state->strategy = strategy;
492     return Z_OK;
493 }
494
495 /* -- see zlib.h -- */
496 int ZEXPORT gzclose_w(file)
497     gzFile file;
498 {
499     int ret;
500     gz_statep state;
501
502     /* get internal structure */
503     if (file == NULL)
504         return Z_STREAM_ERROR;
505     state = (gz_statep)file;
506
507     /* check that we're writing */
508     if (state->mode != GZ_WRITE)
509         return Z_STREAM_ERROR;
510
511     /* check for seek request */
512     if (state->seek) {
513         state->seek = 0;
514         if (gz_zero(state, state->skip) == -1)
515             return -1;
516     }
517
518     /* flush, free memory, and close file */
519     ret = gz_comp(state, Z_FINISH);
520     deflateEnd(&(state->strm));
521     free(state->out);
522     free(state->in);
523     ret += close(state->fd);
524     gz_error(state, Z_OK, NULL);
525     free(state);
526     return ret ? Z_ERRNO : Z_OK;
527 }
528
529 #endif /* !OLD_GZIO */