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