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 */
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. */
gz_init(gz_statep state)15 local 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. */
gz_comp(gz_statep state,int flush)70 local 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. */
gz_zero(gz_statep state,z_off64_t len)133 local 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 -- */
gzwrite(gzFile file,voidpc buf,unsigned len)165 int 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 -- */
gzputc(gzFile file,int c)245 int 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 -- */
gzputs(gzFile file,const char * str)293 int 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 -- */
gzvprintf(gzFile file,const char * format,va_list va)310 int 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
gzprintf(gzFile file,const char * format,...)372 int 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 -- */
gzprintf(gzFile file,const char * format,int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20)386 int 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 -- */
gzflush(gzFile file,int flush)464 int 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 -- */
gzsetparams(gzFile file,int level,int strategy)496 int 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 -- */
gzclose_w(gzFile file)538 int 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