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