gzwrite.c 18.8 KB
Newer Older
1
/* gzwrite.c -- zlib functions for writing gzip files
2
 * Copyright (C) 2004-2017 Mark Adler
3 4 5 6 7 8 9 10 11
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "gzguts.h"

/* Local functions */
local int gz_init OF((gz_statep));
local int gz_comp OF((gz_statep, int));
local int gz_zero OF((gz_statep, z_off64_t));
12
local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));
13 14

/* Initialize state for writing a gzip file.  Mark initialization by setting
15 16
   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
   success. */
17 18 19 20 21 22
local int gz_init(state)
    gz_statep state;
{
    int ret;
    z_streamp strm = &(state->strm);

23 24
    /* allocate input buffer (double size for gzprintf) */
    state->in = (unsigned char *)malloc(state->want << 1);
25
    if (state->in == NULL) {
26 27 28 29
        gz_error(state, Z_MEM_ERROR, "out of memory");
        return -1;
    }

30 31 32
    /* only need output buffer and deflate state if compressing */
    if (!state->direct) {
        /* allocate output buffer */
Roman Donchenko's avatar
Roman Donchenko committed
33
        state->out = (unsigned char *)malloc(state->want);
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
        if (state->out == NULL) {
            free(state->in);
            gz_error(state, Z_MEM_ERROR, "out of memory");
            return -1;
        }

        /* allocate deflate memory, set up for gzip compression */
        strm->zalloc = Z_NULL;
        strm->zfree = Z_NULL;
        strm->opaque = Z_NULL;
        ret = deflateInit2(strm, state->level, Z_DEFLATED,
                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
        if (ret != Z_OK) {
            free(state->out);
            free(state->in);
            gz_error(state, Z_MEM_ERROR, "out of memory");
            return -1;
        }
52
        strm->next_in = NULL;
53 54 55 56 57
    }

    /* mark state as initialized */
    state->size = state->want;

58 59 60 61 62 63
    /* initialize write buffer if compressing */
    if (!state->direct) {
        strm->avail_out = state->size;
        strm->next_out = state->out;
        state->x.next = strm->next_out;
    }
64 65 66 67
    return 0;
}

/* Compress whatever is at avail_in and next_in and write to the output file.
68 69 70 71 72
   Return -1 if there is an error writing to the output file or if gz_init()
   fails to allocate memory, otherwise 0.  flush is assumed to be a valid
   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
   reset to start a new gzip stream.  If gz->direct is true, then simply write
   to the output file without compressing, and ignore flush. */
73 74 75 76
local int gz_comp(state, flush)
    gz_statep state;
    int flush;
{
77 78
    int ret, writ;
    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
79 80 81 82 83 84
    z_streamp strm = &(state->strm);

    /* allocate memory if this is the first time through */
    if (state->size == 0 && gz_init(state) == -1)
        return -1;

85 86
    /* write directly if requested */
    if (state->direct) {
87 88 89 90 91 92 93 94 95
        while (strm->avail_in) {
            put = strm->avail_in > max ? max : strm->avail_in;
            writ = write(state->fd, strm->next_in, put);
            if (writ < 0) {
                gz_error(state, Z_ERRNO, zstrerror());
                return -1;
            }
            strm->avail_in -= (unsigned)writ;
            strm->next_in += writ;
96 97 98 99
        }
        return 0;
    }

100 101 102 103 104 105 106
    /* run deflate() on provided input until it produces no more output */
    ret = Z_OK;
    do {
        /* write out current buffer contents if full, or if flushing, but if
           doing Z_FINISH then don't write until we get to Z_STREAM_END */
        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
            (flush != Z_FINISH || ret == Z_STREAM_END))) {
107 108 109 110 111 112 113 114 115
            while (strm->next_out > state->x.next) {
                put = strm->next_out - state->x.next > (int)max ? max :
                      (unsigned)(strm->next_out - state->x.next);
                writ = write(state->fd, state->x.next, put);
                if (writ < 0) {
                    gz_error(state, Z_ERRNO, zstrerror());
                    return -1;
                }
                state->x.next += writ;
116 117 118 119
            }
            if (strm->avail_out == 0) {
                strm->avail_out = state->size;
                strm->next_out = state->out;
120
                state->x.next = state->out;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
            }
        }

        /* compress */
        have = strm->avail_out;
        ret = deflate(strm, flush);
        if (ret == Z_STREAM_ERROR) {
            gz_error(state, Z_STREAM_ERROR,
                      "internal error: deflate stream corrupt");
            return -1;
        }
        have -= strm->avail_out;
    } while (have);

    /* if that completed a deflate stream, allow another to start */
    if (flush == Z_FINISH)
        deflateReset(strm);

    /* all done, no errors */
    return 0;
}

143 144
/* Compress len zeros to output.  Return -1 on a write error or memory
   allocation failure by gz_comp(), or 0 on success. */
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
local int gz_zero(state, len)
    gz_statep state;
    z_off64_t len;
{
    int first;
    unsigned n;
    z_streamp strm = &(state->strm);

    /* consume whatever's left in the input buffer */
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
        return -1;

    /* compress len zeros (len guaranteed > 0) */
    first = 1;
    while (len) {
        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
            (unsigned)len : state->size;
        if (first) {
            memset(state->in, 0, n);
            first = 0;
        }
        strm->avail_in = n;
        strm->next_in = state->in;
168
        state->x.pos += n;
169 170 171 172 173 174 175
        if (gz_comp(state, Z_NO_FLUSH) == -1)
            return -1;
        len -= n;
    }
    return 0;
}

176 177 178 179
/* Write len bytes from buf to file.  Return the number of bytes written.  If
   the returned value is less than len, then there was an error. */
local z_size_t gz_write(state, buf, len)
    gz_statep state;
180
    voidpc buf;
181
    z_size_t len;
182
{
183
    z_size_t put = len;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203

    /* if len is zero, avoid unnecessary operations */
    if (len == 0)
        return 0;

    /* allocate memory if this is the first time through */
    if (state->size == 0 && gz_init(state) == -1)
        return 0;

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
            return 0;
    }

    /* for small len, copy to input buffer, otherwise compress directly */
    if (len < state->size) {
        /* copy to input buffer, compress when full */
        do {
Roman Donchenko's avatar
Roman Donchenko committed
204 205
            unsigned have, copy;

206 207 208 209
            if (state->strm.avail_in == 0)
                state->strm.next_in = state->in;
            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
                              state->in);
Roman Donchenko's avatar
Roman Donchenko committed
210 211
            copy = state->size - have;
            if (copy > len)
212
                copy = (int)len;
Roman Donchenko's avatar
Roman Donchenko committed
213
            memcpy(state->in + have, buf, copy);
214
            state->strm.avail_in += copy;
Roman Donchenko's avatar
Roman Donchenko committed
215 216 217
            state->x.pos += copy;
            buf = (const char *)buf + copy;
            len -= copy;
218 219 220 221 222 223
            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
                return 0;
        } while (len);
    }
    else {
        /* consume whatever's left in the input buffer */
224
        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
225 226 227
            return 0;

        /* directly compress user buffer to file */
228 229 230 231
        state->strm.next_in = (z_const Bytef *)buf;
        do {
            unsigned n = (unsigned)-1;
            if (n > len)
232
                n = (int)len;
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
            state->strm.avail_in = n;
            state->x.pos += n;
            if (gz_comp(state, Z_NO_FLUSH) == -1)
                return 0;
            len -= n;
        } while (len);
    }

    /* input was all buffered or compressed */
    return put;
}

/* -- see zlib.h -- */
int ZEXPORT gzwrite(file, buf, len)
    gzFile file;
    voidpc buf;
    unsigned len;
{
    gz_statep state;

    /* get internal structure */
    if (file == NULL)
        return 0;
    state = (gz_statep)file;

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return 0;

    /* since an int is returned, make sure len fits in one, otherwise return
       with an error (this avoids a flaw in the interface) */
    if ((int)len < 0) {
        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
        return 0;
    }

    /* write len bytes from buf (the return value will fit in an int) */
    return (int)gz_write(state, buf, len);
}

/* -- see zlib.h -- */
z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
    voidpc buf;
    z_size_t size;
    z_size_t nitems;
    gzFile file;
{
    z_size_t len;
    gz_statep state;

    /* get internal structure */
    if (file == NULL)
        return 0;
    state = (gz_statep)file;

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return 0;

    /* compute bytes to read -- error on overflow */
    len = nitems * size;
    if (size && len / size != nitems) {
        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
        return 0;
297 298
    }

299 300
    /* write len bytes to buf, return the number of full items written */
    return len ? gz_write(state, buf, len) / size : 0;
301 302 303 304 305 306 307
}

/* -- see zlib.h -- */
int ZEXPORT gzputc(file, c)
    gzFile file;
    int c;
{
Roman Donchenko's avatar
Roman Donchenko committed
308
    unsigned have;
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    unsigned char buf[1];
    gz_statep state;
    z_streamp strm;

    /* get internal structure */
    if (file == NULL)
        return -1;
    state = (gz_statep)file;
    strm = &(state->strm);

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return -1;

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
            return -1;
    }

    /* try writing to input buffer for speed (state->size == 0 if buffer not
       initialized) */
Roman Donchenko's avatar
Roman Donchenko committed
332
    if (state->size) {
333 334
        if (strm->avail_in == 0)
            strm->next_in = state->in;
Roman Donchenko's avatar
Roman Donchenko committed
335 336
        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
        if (have < state->size) {
337
            state->in[have] = (unsigned char)c;
Roman Donchenko's avatar
Roman Donchenko committed
338 339 340 341
            strm->avail_in++;
            state->x.pos++;
            return c & 0xff;
        }
342 343 344
    }

    /* no room in buffer or not initialized, use gz_write() */
345 346
    buf[0] = (unsigned char)c;
    if (gz_write(state, buf, 1) != 1)
347
        return -1;
348
    return c & 0xff;
349 350 351 352 353 354 355 356
}

/* -- see zlib.h -- */
int ZEXPORT gzputs(file, str)
    gzFile file;
    const char *str;
{
    int ret;
357 358 359 360 361 362 363 364 365 366 367
    z_size_t len;
    gz_statep state;

    /* get internal structure */
    if (file == NULL)
        return -1;
    state = (gz_statep)file;

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return -1;
368 369

    /* write string */
370
    len = strlen(str);
371
    ret = (int)gz_write(state, str, len);
372 373 374
    return ret == 0 && len != 0 ? -1 : ret;
}

375
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
376 377 378
#include <stdarg.h>

/* -- see zlib.h -- */
Roman Donchenko's avatar
Roman Donchenko committed
379
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
380
{
381 382 383
    int len;
    unsigned left;
    char *next;
384 385 386 387 388
    gz_statep state;
    z_streamp strm;

    /* get internal structure */
    if (file == NULL)
389
        return Z_STREAM_ERROR;
390 391 392 393 394
    state = (gz_statep)file;
    strm = &(state->strm);

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
395
        return Z_STREAM_ERROR;
396 397 398

    /* make sure we have some buffer space */
    if (state->size == 0 && gz_init(state) == -1)
399
        return state->err;
400 401 402 403 404

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
405
            return state->err;
406 407
    }

408 409 410 411 412 413 414
    /* do the printf() into the input buffer, put length in len -- the input
       buffer is double-sized just for this function, so there is guaranteed to
       be state->size bytes available after the current contents */
    if (strm->avail_in == 0)
        strm->next_in = state->in;
    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
    next[state->size - 1] = 0;
415 416
#ifdef NO_vsnprintf
#  ifdef HAS_vsprintf_void
417 418 419
    (void)vsprintf(next, format, va);
    for (len = 0; len < state->size; len++)
        if (next[len] == 0) break;
420
#  else
421
    len = vsprintf(next, format, va);
422 423 424
#  endif
#else
#  ifdef HAS_vsnprintf_void
425 426
    (void)vsnprintf(next, state->size, format, va);
    len = strlen(next);
427
#  else
428
    len = vsnprintf(next, state->size, format, va);
429 430 431 432
#  endif
#endif

    /* check that printf() results fit in buffer */
433
    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
434 435
        return 0;

436 437
    /* update buffer and position, compress first half if past that */
    strm->avail_in += (unsigned)len;
438
    state->x.pos += len;
439 440 441 442 443 444 445 446 447
    if (strm->avail_in >= state->size) {
        left = strm->avail_in - state->size;
        strm->avail_in = state->size;
        if (gz_comp(state, Z_NO_FLUSH) == -1)
            return state->err;
        memcpy(state->in, state->in + state->size, left);
        strm->next_in = state->in;
        strm->avail_in = left;
    }
448 449 450
    return len;
}

Roman Donchenko's avatar
Roman Donchenko committed
451 452 453 454 455 456 457 458 459 460 461
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
{
    va_list va;
    int ret;

    va_start(va, format);
    ret = gzvprintf(file, format, va);
    va_end(va);
    return ret;
}

462
#else /* !STDC && !Z_HAVE_STDARG_H */
463 464 465 466 467 468 469 470 471

/* -- see zlib.h -- */
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
    gzFile file;
    const char *format;
    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
{
472 473
    unsigned len, left;
    char *next;
474 475 476 477 478
    gz_statep state;
    z_streamp strm;

    /* get internal structure */
    if (file == NULL)
479
        return Z_STREAM_ERROR;
480 481 482
    state = (gz_statep)file;
    strm = &(state->strm);

483 484
    /* check that can really pass pointer in ints */
    if (sizeof(int) != sizeof(void *))
485
        return Z_STREAM_ERROR;
486

487 488
    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
489
        return Z_STREAM_ERROR;
490 491 492

    /* make sure we have some buffer space */
    if (state->size == 0 && gz_init(state) == -1)
493
        return state->error;
494 495 496 497 498

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
499
            return state->error;
500 501
    }

502 503 504 505 506 507 508
    /* do the printf() into the input buffer, put length in len -- the input
       buffer is double-sized just for this function, so there is guaranteed to
       be state->size bytes available after the current contents */
    if (strm->avail_in == 0)
        strm->next_in = state->in;
    next = (char *)(strm->next_in + strm->avail_in);
    next[state->size - 1] = 0;
509 510
#ifdef NO_snprintf
#  ifdef HAS_sprintf_void
511 512
    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
            a13, a14, a15, a16, a17, a18, a19, a20);
513
    for (len = 0; len < size; len++)
514 515
        if (next[len] == 0)
            break;
516
#  else
517 518
    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
                  a12, a13, a14, a15, a16, a17, a18, a19, a20);
519 520 521
#  endif
#else
#  ifdef HAS_snprintf_void
522 523 524
    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
    len = strlen(next);
525
#  else
526 527
    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
528 529 530 531
#  endif
#endif

    /* check that printf() results fit in buffer */
532
    if (len == 0 || len >= state->size || next[state->size - 1] != 0)
533 534
        return 0;

535 536
    /* update buffer and position, compress first half if past that */
    strm->avail_in += len;
537
    state->x.pos += len;
538 539 540 541 542 543 544 545 546 547
    if (strm->avail_in >= state->size) {
        left = strm->avail_in - state->size;
        strm->avail_in = state->size;
        if (gz_comp(state, Z_NO_FLUSH) == -1)
            return state->err;
        memcpy(state->in, state->in + state->size, left);
        strm->next_in = state->in;
        strm->avail_in = left;
    }
    return (int)len;
548 549 550 551 552 553 554 555 556 557 558 559 560
}

#endif

/* -- see zlib.h -- */
int ZEXPORT gzflush(file, flush)
    gzFile file;
    int flush;
{
    gz_statep state;

    /* get internal structure */
    if (file == NULL)
561
        return Z_STREAM_ERROR;
562 563 564 565 566 567 568 569 570 571 572 573 574 575
    state = (gz_statep)file;

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return Z_STREAM_ERROR;

    /* check flush parameter */
    if (flush < 0 || flush > Z_FINISH)
        return Z_STREAM_ERROR;

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
576
            return state->err;
577 578 579
    }

    /* compress remaining data with requested flush */
580
    (void)gz_comp(state, flush);
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
    return state->err;
}

/* -- see zlib.h -- */
int ZEXPORT gzsetparams(file, level, strategy)
    gzFile file;
    int level;
    int strategy;
{
    gz_statep state;
    z_streamp strm;

    /* get internal structure */
    if (file == NULL)
        return Z_STREAM_ERROR;
    state = (gz_statep)file;
    strm = &(state->strm);

    /* check that we're writing and that there's no error */
    if (state->mode != GZ_WRITE || state->err != Z_OK)
        return Z_STREAM_ERROR;

    /* if no change is requested, then do nothing */
    if (level == state->level && strategy == state->strategy)
        return Z_OK;

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
        if (gz_zero(state, state->skip) == -1)
611
            return state->err;
612 613 614 615 616
    }

    /* change compression parameters for subsequent input */
    if (state->size) {
        /* flush previous input with previous parameters before changing */
617
        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
618 619 620 621 622 623 624 625 626 627 628 629
            return state->err;
        deflateParams(strm, level, strategy);
    }
    state->level = level;
    state->strategy = strategy;
    return Z_OK;
}

/* -- see zlib.h -- */
int ZEXPORT gzclose_w(file)
    gzFile file;
{
630
    int ret = Z_OK;
631 632 633 634 635 636 637 638 639 640 641 642 643 644
    gz_statep state;

    /* get internal structure */
    if (file == NULL)
        return Z_STREAM_ERROR;
    state = (gz_statep)file;

    /* check that we're writing */
    if (state->mode != GZ_WRITE)
        return Z_STREAM_ERROR;

    /* check for seek request */
    if (state->seek) {
        state->seek = 0;
645 646
        if (gz_zero(state, state->skip) == -1)
            ret = state->err;
647 648 649
    }

    /* flush, free memory, and close file */
Roman Donchenko's avatar
Roman Donchenko committed
650 651
    if (gz_comp(state, Z_FINISH) == -1)
        ret = state->err;
652 653 654 655 656 657
    if (state->size) {
        if (!state->direct) {
            (void)deflateEnd(&(state->strm));
            free(state->out);
        }
        free(state->in);
658
    }
659 660
    gz_error(state, Z_OK, NULL);
    free(state->path);
661 662
    if (close(state->fd) == -1)
        ret = Z_ERRNO;
663
    free(state);
664 665
    return ret;
}