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. */
  15 local int gz_init(state)
  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. */
  70 local int gz_comp(state, flush)
  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. */
 133 local int gz_zero(state, len)
 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 -- */
 165 int ZEXPORT gzwrite(file, buf, len)
 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 -- */
 245 int ZEXPORT gzputc(file, c)
 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 -- */
 293 int ZEXPORT gzputs(file, str)
 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 -- */
 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 
 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 -- */
 386 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
 387                        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
 388     gzFile file;
 389     const char *format;
 390     int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
 391         a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
 392 {
 393     int size, len;
 394     gz_statep state;
 395     z_streamp strm;
 396 
 397     /* get internal structure */
 398     if (file == NULL)
 399         return -1;
 400     state = (gz_statep)file;
 401     strm = &(state->strm);
 402 
 403     /* check that can really pass pointer in ints */
 404     if (sizeof(int) != sizeof(void *))
 405         return 0;
 406 
 407     /* check that we're writing and that there's no error */
 408     if (state->mode != GZ_WRITE || state->err != Z_OK)
 409         return 0;
 410 
 411     /* make sure we have some buffer space */
 412     if (state->size == 0 && gz_init(state) == -1)
 413         return 0;
 414 
 415     /* check for seek request */
 416     if (state->seek) {
 417         state->seek = 0;
 418         if (gz_zero(state, state->skip) == -1)
 419             return 0;
 420     }
 421 
 422     /* consume whatever's left in the input buffer */
 423     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
 424         return 0;
 425 
 426     /* do the printf() into the input buffer, put length in len */
 427     size = (int)(state->size);
 428     state->in[size - 1] = 0;
 429 #ifdef NO_snprintf
 430 #  ifdef HAS_sprintf_void
 431     sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
 432             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
 433     for (len = 0; len < size; len++)
 434         if (state->in[len] == 0) break;
 435 #  else
 436     len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
 437                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
 438 #  endif
 439 #else
 440 #  ifdef HAS_snprintf_void
 441     snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8,
 442              a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
 443     len = strlen((char *)(state->in));
 444 #  else
 445     len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6,
 446                    a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18,
 447                    a19, a20);
 448 #  endif
 449 #endif
 450 
 451     /* check that printf() results fit in buffer */
 452     if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
 453         return 0;
 454 
 455     /* update buffer and position, defer compression until needed */
 456     strm->avail_in = (unsigned)len;
 457     strm->next_in = state->in;
 458     state->x.pos += len;
 459     return len;
 460 }
 461 
 462 #endif
 463 
 464 /* -- see zlib.h -- */
 465 int ZEXPORT gzflush(file, flush)
 466     gzFile file;
 467     int flush;
 468 {
 469     gz_statep state;
 470 
 471     /* get internal structure */
 472     if (file == NULL)
 473         return -1;
 474     state = (gz_statep)file;
 475 
 476     /* check that we're writing and that there's no error */
 477     if (state->mode != GZ_WRITE || state->err != Z_OK)
 478         return Z_STREAM_ERROR;
 479 
 480     /* check flush parameter */
 481     if (flush < 0 || flush > Z_FINISH)
 482         return Z_STREAM_ERROR;
 483 
 484     /* check for seek request */
 485     if (state->seek) {
 486         state->seek = 0;
 487         if (gz_zero(state, state->skip) == -1)
 488             return -1;
 489     }
 490 
 491     /* compress remaining data with requested flush */
 492     gz_comp(state, flush);
 493     return state->err;
 494 }
 495 
 496 /* -- see zlib.h -- */
 497 int ZEXPORT gzsetparams(file, level, strategy)
 498     gzFile file;
 499     int level;
 500     int strategy;
 501 {
 502     gz_statep state;
 503     z_streamp strm;
 504 
 505     /* get internal structure */
 506     if (file == NULL)
 507         return Z_STREAM_ERROR;
 508     state = (gz_statep)file;
 509     strm = &(state->strm);
 510 
 511     /* check that we're writing and that there's no error */
 512     if (state->mode != GZ_WRITE || state->err != Z_OK)
 513         return Z_STREAM_ERROR;
 514 
 515     /* if no change is requested, then do nothing */
 516     if (level == state->level && strategy == state->strategy)
 517         return Z_OK;
 518 
 519     /* check for seek request */
 520     if (state->seek) {
 521         state->seek = 0;
 522         if (gz_zero(state, state->skip) == -1)
 523             return -1;
 524     }
 525 
 526     /* change compression parameters for subsequent input */
 527     if (state->size) {
 528         /* flush previous input with previous parameters before changing */
 529         if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
 530             return state->err;
 531         deflateParams(strm, level, strategy);
 532     }
 533     state->level = level;
 534     state->strategy = strategy;
 535     return Z_OK;
 536 }
 537 
 538 /* -- see zlib.h -- */
 539 int ZEXPORT gzclose_w(file)
 540     gzFile file;
 541 {
 542     int ret = Z_OK;
 543     gz_statep state;
 544 
 545     /* get internal structure */
 546     if (file == NULL)
 547         return Z_STREAM_ERROR;
 548     state = (gz_statep)file;
 549 
 550     /* check that we're writing */
 551     if (state->mode != GZ_WRITE)
 552         return Z_STREAM_ERROR;
 553 
 554     /* check for seek request */
 555     if (state->seek) {
 556         state->seek = 0;
 557         if (gz_zero(state, state->skip) == -1)
 558             ret = state->err;
 559     }
 560 
 561     /* flush, free memory, and close file */
 562     if (gz_comp(state, Z_FINISH) == -1)
 563         ret = state->err;
 564     if (state->size) {
 565         if (!state->direct) {
 566             (void)deflateEnd(&(state->strm));
 567             free(state->out);
 568         }
 569         free(state->in);
 570     }
 571     gz_error(state, Z_OK, NULL);
 572     free(state->path);
 573     if (close(state->fd) == -1)
 574         ret = Z_ERRNO;
 575     free(state);
 576     return ret;
 577 }