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
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));
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)
21 z_streamp strm = &(state->strm);
23 /* check version of zlib -- need 1.2.1 or later for gzip deflate() */
25 if (ZLIB_VERNUM < 0x1210)
28 gz_error(state, Z_VERSION_ERROR, "need zlib 1.2.1 or later");
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)
38 if (state->in != NULL)
40 gz_error(state, Z_MEM_ERROR, "out of memory");
44 /* allocate deflate memory, set up for gzip compression */
45 strm->zalloc = Z_NULL;
47 strm->opaque = Z_NULL;
48 ret = deflateInit2(strm, state->level, Z_DEFLATED,
49 15 + 16, 8, state->strategy);
52 gz_error(state, Z_MEM_ERROR, "out of memory");
56 /* mark state as initialized */
57 state->size = state->want;
59 /* initialize write buffer */
60 strm->avail_out = state->size;
61 strm->next_out = state->out;
62 state->next = strm->next_out;
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)
76 z_streamp strm = &(state->strm);
78 /* allocate memory if this is the first time through */
79 if (state->size == 0 && gz_init(state) == -1)
82 /* run deflate() on provided input until it produces no more output */
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());
94 if (strm->avail_out == 0) {
95 strm->avail_out = state->size;
96 strm->next_out = state->out;
98 state->next = strm->next_out;
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");
109 have -= strm->avail_out;
112 /* if that completed a deflate stream, allow another to start */
113 if (flush == Z_FINISH)
116 /* all done, no errors */
120 /* Compress len zeros to output. Return -1 on error, 0 on success. */
121 local int gz_zero(state, len)
127 z_streamp strm = &(state->strm);
129 /* consume whatever's left in the input buffer */
130 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
133 /* compress len zeros */
136 n = len < state->size ? (unsigned)len : state->size;
138 memset(state->in, 0, n);
142 strm->next_in = state->in;
144 if (gz_comp(state, Z_NO_FLUSH) == -1)
151 /* -- see zlib.h -- */
152 int ZEXPORT gzwrite(file, buf, len)
162 /* get internal structure */
165 state = (gz_statep)file;
166 strm = &(state->strm);
168 /* check that we're writing and that there's no error */
169 if (state->mode != GZ_WRITE || state->err != Z_OK)
172 /* allocate memory if this is the first time through */
173 if (state->size == 0 && gz_init(state) == -1)
176 /* check for seek request */
179 if (gz_zero(state, state->skip) == -1)
183 /* for small len, copy to input buffer, otherwise compress directly */
184 if (len < state->size) {
185 /* copy to input buffer, compress when full */
187 if (strm->avail_in == 0)
188 strm->next_in = state->in;
189 n = state->size - strm->avail_in;
192 memcpy(strm->next_in + strm->avail_in, buf, n);
197 if (len && gz_comp(state, Z_NO_FLUSH) == -1)
202 /* consume whatever's left in the input buffer */
203 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
206 /* directly compress user buffer to file */
207 strm->avail_in = len;
208 strm->next_in = (voidp)buf;
210 if (gz_comp(state, Z_NO_FLUSH) == -1)
214 /* input was all buffered or compressed */
218 /* -- see zlib.h -- */
219 int ZEXPORT gzputc(file, c)
223 unsigned char buf[1];
227 /* get internal structure */
230 state = (gz_statep)file;
231 strm = &(state->strm);
233 /* check that we're writing and that there's no error */
234 if (state->mode != GZ_WRITE || state->err != Z_OK)
237 /* check for seek request */
240 if (gz_zero(state, state->skip) == -1)
244 /* try writing to input buffer for speed (state->size == 0 if buffer not
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;
254 /* no room in buffer or not initialized, use gz_write() */
256 if (gzwrite(file, buf, 1) != 1)
261 /* -- see zlib.h -- */
262 int ZEXPORT gzputs(file, str)
267 return gzwrite(file, str, strlen(str));
273 /* -- see zlib.h -- */
274 int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
281 /* get internal structure */
284 state = (gz_statep)file;
285 strm = &(state->strm);
287 /* check that we're writing and that there's no error */
288 if (state->mode != GZ_WRITE || state->err != Z_OK)
291 /* make sure we have some buffer space */
292 if (state->size == 0 && gz_init(state) == -1)
295 /* check for seek request */
298 if (gz_zero(state, state->skip) == -1)
302 /* consume whatever's left in the input buffer */
303 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
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);
311 # ifdef HAS_vsprintf_void
312 (void)vsprintf(state->in, format, va);
314 for (len = 0; len < state->in; len++)
315 if (state->in[len] == 0) break;
317 len = vsprintf(state->in, format, va);
321 # ifdef HAS_vsnprintf_void
322 (void)vsnprintf(state->in, size, format, va);
324 len = strlen(state->in);
326 len = vsnprintf((char *)(state->in), size, format, va);
331 /* check that printf() results fit in buffer */
332 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
335 /* write out result of printf() */
336 strm->avail_in = (unsigned)len;
337 strm->next_in = state->in;
339 if (gz_comp(state, Z_NO_FLUSH) == -1)
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)
351 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
352 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
358 /* get internal structure */
361 state = (gz_statep)file;
362 strm = &(state->strm);
364 /* check that we're writing and that there's no error */
365 if (state->mode != GZ_WRITE || state->err != Z_OK)
368 /* make sure we have some buffer space */
369 if (state->size == 0 && gz_init(state) == -1)
372 /* check for seek request */
375 if (gz_zero(state, state->skip) == -1)
379 /* consume whatever's left in the input buffer */
380 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
383 /* do the printf() into the input buffer, put length in len */
384 size = (int)(state->size);
385 state->in[size - 1] = 0;
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;
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);
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);
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);
407 /* check that printf() results fit in buffer */
408 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
411 /* write out result of printf() */
412 strm->avail_in = (unsigned)len;
413 strm->next_in = state->in;
415 if (gz_comp(state, Z_NO_FLUSH) == -1)
422 /* -- see zlib.h -- */
423 int ZEXPORT gzflush(file, flush)
429 /* get internal structure */
432 state = (gz_statep)file;
434 /* check that we're writing and that there's no error */
435 if (state->mode != GZ_WRITE|| state->err != Z_OK)
437 /* check flush parameter */
438 if (flush < 0 || flush > Z_FINISH)
439 return Z_STREAM_ERROR;
441 /* check for seek request */
444 if (gz_zero(state, state->skip) == -1)
448 /* compress remaining data with requested flush */
449 gz_comp(state, flush);
453 /* -- see zlib.h -- */
454 int ZEXPORT gzsetparams(file, level, strategy)
462 /* get internal structure */
464 return Z_STREAM_ERROR;
465 state = (gz_statep)file;
466 strm = &(state->strm);
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;
472 /* if no change is requested, then do nothing */
473 if (level == state->level && strategy == state->strategy)
476 /* check for seek request */
479 if (gz_zero(state, state->skip) == -1)
483 /* change compression parameters for subsequent input */
485 /* flush previous input with previous parameters before changing */
486 if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
488 deflateParams(strm, level, strategy);
490 state->level = level;
491 state->strategy = strategy;
495 /* -- see zlib.h -- */
496 int ZEXPORT gzclose_w(file)
502 /* get internal structure */
504 return Z_STREAM_ERROR;
505 state = (gz_statep)file;
507 /* check that we're writing */
508 if (state->mode != GZ_WRITE)
509 return Z_STREAM_ERROR;
511 /* check for seek request */
514 if (gz_zero(state, state->skip) == -1)
518 /* flush, free memory, and close file */
519 ret = gz_comp(state, Z_FINISH);
520 deflateEnd(&(state->strm));
523 ret += close(state->fd);
524 gz_error(state, Z_OK, NULL);
526 return ret ? Z_ERRNO : Z_OK;
529 #endif /* !OLD_GZIO */