1/* gzwrite.c -- zlib functions for writing gzip files
2 * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 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 */
9local int gz_init OF((gz_statep));
10local int gz_comp OF((gz_statep, int));
11local 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. */
15local int gz_init(
16    gz_statep state)
17{
18    int ret;
19    z_streamp strm = &(state->strm);
20
21    /* allocate input buffer */
22    state->in = (unsigned char *)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 = (unsigned char *)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. */
70local int gz_comp(
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. */
133local int gz_zero(
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 -- */
165int ZEXPORT gzwrite(
166    gzFile file,
167    voidpc buf,
168    unsigned len)
169{
170    unsigned put = len;
171    gz_statep state;
172    z_streamp strm;
173
174    /* get internal structure */
175    if (file == NULL)
176        return 0;
177    state = (gz_statep)file;
178    strm = &(state->strm);
179
180    /* check that we're writing and that there's no error */
181    if (state->mode != GZ_WRITE || state->err != Z_OK)
182        return 0;
183
184    /* since an int is returned, make sure len fits in one, otherwise return
185       with an error (this avoids the flaw in the interface) */
186    if ((int)len < 0) {
187        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
188        return 0;
189    }
190
191    /* if len is zero, avoid unnecessary operations */
192    if (len == 0)
193        return 0;
194
195    /* allocate memory if this is the first time through */
196    if (state->size == 0 && gz_init(state) == -1)
197        return 0;
198
199    /* check for seek request */
200    if (state->seek) {
201        state->seek = 0;
202        if (gz_zero(state, state->skip) == -1)
203            return 0;
204    }
205
206    /* for small len, copy to input buffer, otherwise compress directly */
207    if (len < state->size) {
208        /* copy to input buffer, compress when full */
209        do {
210            unsigned have, copy;
211
212            if (strm->avail_in == 0)
213                strm->next_in = state->in;
214            have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
215            copy = state->size - have;
216            if (copy > len)
217                copy = len;
218            memcpy(state->in + have, buf, copy);
219            strm->avail_in += copy;
220            state->x.pos += copy;
221            buf = (const char *)buf + copy;
222            len -= copy;
223            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
224                return 0;
225        } while (len);
226    }
227    else {
228        /* consume whatever's left in the input buffer */
229        if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
230            return 0;
231
232        /* directly compress user buffer to file */
233        strm->avail_in = len;
234        strm->next_in = (z_const Bytef *)buf;
235        state->x.pos += len;
236        if (gz_comp(state, Z_NO_FLUSH) == -1)
237            return 0;
238    }
239
240    /* input was all buffered or compressed (put will fit in int) */
241    return (int)put;
242}
243
244/* -- see zlib.h -- */
245int ZEXPORT gzputc(
246    gzFile file,
247    int c)
248{
249    unsigned have;
250    unsigned char buf[1];
251    gz_statep state;
252    z_streamp strm;
253
254    /* get internal structure */
255    if (file == NULL)
256        return -1;
257    state = (gz_statep)file;
258    strm = &(state->strm);
259
260    /* check that we're writing and that there's no error */
261    if (state->mode != GZ_WRITE || state->err != Z_OK)
262        return -1;
263
264    /* check for seek request */
265    if (state->seek) {
266        state->seek = 0;
267        if (gz_zero(state, state->skip) == -1)
268            return -1;
269    }
270
271    /* try writing to input buffer for speed (state->size == 0 if buffer not
272       initialized) */
273    if (state->size) {
274        if (strm->avail_in == 0)
275            strm->next_in = state->in;
276        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
277        if (have < state->size) {
278            state->in[have] = c;
279            strm->avail_in++;
280            state->x.pos++;
281            return c & 0xff;
282        }
283    }
284
285    /* no room in buffer or not initialized, use gz_write() */
286    buf[0] = c;
287    if (gzwrite(file, buf, 1) != 1)
288        return -1;
289    return c & 0xff;
290}
291
292/* -- see zlib.h -- */
293int ZEXPORT gzputs(
294    gzFile file,
295    const char *str)
296{
297    int ret;
298    unsigned len;
299
300    /* write string */
301    len = (unsigned)strlen(str);
302    ret = gzwrite(file, str, len);
303    return ret == 0 && len != 0 ? -1 : ret;
304}
305
306#if defined(STDC) || defined(Z_HAVE_STDARG_H)
307#include <stdarg.h>
308
309/* -- see zlib.h -- */
310int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
311{
312    int size, len;
313    gz_statep state;
314    z_streamp strm;
315
316    /* get internal structure */
317    if (file == NULL)
318        return -1;
319    state = (gz_statep)file;
320    strm = &(state->strm);
321
322    /* check that we're writing and that there's no error */
323    if (state->mode != GZ_WRITE || state->err != Z_OK)
324        return 0;
325
326    /* make sure we have some buffer space */
327    if (state->size == 0 && gz_init(state) == -1)
328        return 0;
329
330    /* check for seek request */
331    if (state->seek) {
332        state->seek = 0;
333        if (gz_zero(state, state->skip) == -1)
334            return 0;
335    }
336
337    /* consume whatever's left in the input buffer */
338    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
339        return 0;
340
341    /* do the printf() into the input buffer, put length in len */
342    size = (int)(state->size);
343    state->in[size - 1] = 0;
344#ifdef NO_vsnprintf
345#  ifdef HAS_vsprintf_void
346    (void)vsprintf((char *)(state->in), format, va);
347    for (len = 0; len < size; len++)
348        if (state->in[len] == 0) break;
349#  else
350    len = vsprintf((char *)(state->in), format, va);
351#  endif
352#else
353#  ifdef HAS_vsnprintf_void
354    (void)vsnprintf((char *)(state->in), size, format, va);
355    len = strlen((char *)(state->in));
356#  else
357    len = vsnprintf((char *)(state->in), size, format, va);
358#  endif
359#endif
360
361    /* check that printf() results fit in buffer */
362    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
363        return 0;
364
365    /* update buffer and position, defer compression until needed */
366    strm->avail_in = (unsigned)len;
367    strm->next_in = state->in;
368    state->x.pos += len;
369    return len;
370}
371
372int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
373{
374    va_list va;
375    int ret;
376
377    va_start(va, format);
378    ret = gzvprintf(file, format, va);
379    va_end(va);
380    return ret;
381}
382
383#else /* !STDC && !Z_HAVE_STDARG_H */
384
385/* -- see zlib.h -- */
386int ZEXPORTVA gzprintf (
387    gzFile file,
388    const char *format,
389    int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10,
390        int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20)
391{
392    int size, len;
393    gz_statep state;
394    z_streamp strm;
395
396    /* get internal structure */
397    if (file == NULL)
398        return -1;
399    state = (gz_statep)file;
400    strm = &(state->strm);
401
402    /* check that can really pass pointer in ints */
403    if (sizeof(int) != sizeof(void *))
404        return 0;
405
406    /* check that we're writing and that there's no error */
407    if (state->mode != GZ_WRITE || state->err != Z_OK)
408        return 0;
409
410    /* make sure we have some buffer space */
411    if (state->size == 0 && gz_init(state) == -1)
412        return 0;
413
414    /* check for seek request */
415    if (state->seek) {
416        state->seek = 0;
417        if (gz_zero(state, state->skip) == -1)
418            return 0;
419    }
420
421    /* consume whatever's left in the input buffer */
422    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
423        return 0;
424
425    /* do the printf() into the input buffer, put length in len */
426    size = (int)(state->size);
427    state->in[size - 1] = 0;
428#ifdef NO_snprintf
429#  ifdef HAS_sprintf_void
430    sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
431            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
432    for (len = 0; len < size; len++)
433        if (state->in[len] == 0) break;
434#  else
435    len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
436                  a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
437#  endif
438#else
439#  ifdef HAS_snprintf_void
440    snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8,
441             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
442    len = strlen((char *)(state->in));
443#  else
444    len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6,
445                   a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18,
446                   a19, a20);
447#  endif
448#endif
449
450    /* check that printf() results fit in buffer */
451    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
452        return 0;
453
454    /* update buffer and position, defer compression until needed */
455    strm->avail_in = (unsigned)len;
456    strm->next_in = state->in;
457    state->x.pos += len;
458    return len;
459}
460
461#endif
462
463/* -- see zlib.h -- */
464int ZEXPORT gzflush(
465    gzFile file,
466    int flush)
467{
468    gz_statep state;
469
470    /* get internal structure */
471    if (file == NULL)
472        return -1;
473    state = (gz_statep)file;
474
475    /* check that we're writing and that there's no error */
476    if (state->mode != GZ_WRITE || state->err != Z_OK)
477        return Z_STREAM_ERROR;
478
479    /* check flush parameter */
480    if (flush < 0 || flush > Z_FINISH)
481        return Z_STREAM_ERROR;
482
483    /* check for seek request */
484    if (state->seek) {
485        state->seek = 0;
486        if (gz_zero(state, state->skip) == -1)
487            return -1;
488    }
489
490    /* compress remaining data with requested flush */
491    gz_comp(state, flush);
492    return state->err;
493}
494
495/* -- see zlib.h -- */
496int ZEXPORT gzsetparams(
497    gzFile file,
498    int level,
499    int strategy)
500{
501    gz_statep state;
502    z_streamp strm;
503
504    /* get internal structure */
505    if (file == NULL)
506        return Z_STREAM_ERROR;
507    state = (gz_statep)file;
508    strm = &(state->strm);
509
510    /* check that we're writing and that there's no error */
511    if (state->mode != GZ_WRITE || state->err != Z_OK)
512        return Z_STREAM_ERROR;
513
514    /* if no change is requested, then do nothing */
515    if (level == state->level && strategy == state->strategy)
516        return Z_OK;
517
518    /* check for seek request */
519    if (state->seek) {
520        state->seek = 0;
521        if (gz_zero(state, state->skip) == -1)
522            return -1;
523    }
524
525    /* change compression parameters for subsequent input */
526    if (state->size) {
527        /* flush previous input with previous parameters before changing */
528        if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
529            return state->err;
530        deflateParams(strm, level, strategy);
531    }
532    state->level = level;
533    state->strategy = strategy;
534    return Z_OK;
535}
536
537/* -- see zlib.h -- */
538int ZEXPORT gzclose_w(
539    gzFile file)
540{
541    int ret = Z_OK;
542    gz_statep state;
543
544    /* get internal structure */
545    if (file == NULL)
546        return Z_STREAM_ERROR;
547    state = (gz_statep)file;
548
549    /* check that we're writing */
550    if (state->mode != GZ_WRITE)
551        return Z_STREAM_ERROR;
552
553    /* check for seek request */
554    if (state->seek) {
555        state->seek = 0;
556        if (gz_zero(state, state->skip) == -1)
557            ret = state->err;
558    }
559
560    /* flush, free memory, and close file */
561    if (gz_comp(state, Z_FINISH) == -1)
562        ret = state->err;
563    if (state->size) {
564        if (!state->direct) {
565            (void)deflateEnd(&(state->strm));
566            free(state->out);
567        }
568        free(state->in);
569    }
570    gz_error(state, Z_OK, NULL);
571    free(state->path);
572    if (close(state->fd) == -1)
573        ret = Z_ERRNO;
574    free(state);
575    return ret;
576}
577