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