1 /* gzwrite.c contains minimal changes required to be compiled with zlibWrapper: 2 * - gz_statep was converted to union to work with -Wstrict-aliasing=1 */ 3 4 /* gzwrite.c -- zlib functions for writing gzip files 5 * Copyright (C) 2004-2017 Mark Adler 6 * For conditions of distribution and use, see http://www.zlib.net/zlib_license.html 7 */ 8 9 #include <assert.h> 10 11 #include "gzguts.h" 12 13 /* Local functions */ 14 local int gz_init OF((gz_statep)); 15 local int gz_comp OF((gz_statep, int)); 16 local int gz_zero OF((gz_statep, z_off64_t)); 17 local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); 18 19 /* Initialize state for writing a gzip file. Mark initialization by setting 20 state.state->size to non-zero. Return -1 on a memory allocation failure, or 0 on 21 success. */ 22 local int gz_init(state) 23 gz_statep state; 24 { 25 int ret; 26 z_streamp strm = &(state.state->strm); 27 28 /* allocate input buffer (double size for gzprintf) */ 29 state.state->in = (unsigned char*)malloc(state.state->want << 1); 30 if (state.state->in == NULL) { 31 gz_error(state, Z_MEM_ERROR, "out of memory"); 32 return -1; 33 } 34 35 /* only need output buffer and deflate state if compressing */ 36 if (!state.state->direct) { 37 /* allocate output buffer */ 38 state.state->out = (unsigned char*)malloc(state.state->want); 39 if (state.state->out == NULL) { 40 free(state.state->in); 41 gz_error(state, Z_MEM_ERROR, "out of memory"); 42 return -1; 43 } 44 45 /* allocate deflate memory, set up for gzip compression */ 46 strm->zalloc = Z_NULL; 47 strm->zfree = Z_NULL; 48 strm->opaque = Z_NULL; 49 ret = deflateInit2(strm, state.state->level, Z_DEFLATED, 50 MAX_WBITS + 16, DEF_MEM_LEVEL, state.state->strategy); 51 if (ret != Z_OK) { 52 free(state.state->out); 53 free(state.state->in); 54 gz_error(state, Z_MEM_ERROR, "out of memory"); 55 return -1; 56 } 57 strm->next_in = NULL; 58 } 59 60 /* mark state as initialized */ 61 state.state->size = state.state->want; 62 63 /* initialize write buffer if compressing */ 64 if (!state.state->direct) { 65 strm->avail_out = state.state->size; 66 strm->next_out = state.state->out; 67 state.state->x.next = strm->next_out; 68 } 69 return 0; 70 } 71 72 /* Compress whatever is at avail_in and next_in and write to the output file. 73 Return -1 if there is an error writing to the output file or if gz_init() 74 fails to allocate memory, otherwise 0. flush is assumed to be a valid 75 deflate() flush value. If flush is Z_FINISH, then the deflate() state is 76 reset to start a new gzip stream. If gz->direct is true, then simply write 77 to the output file without compressing, and ignore flush. */ 78 local int gz_comp(state, flush) 79 gz_statep state; 80 int flush; 81 { 82 int ret, writ; 83 unsigned have, put, max = ((unsigned)-1 >> 2) + 1; 84 z_streamp strm = &(state.state->strm); 85 86 /* allocate memory if this is the first time through */ 87 if (state.state->size == 0 && gz_init(state) == -1) 88 return -1; 89 90 /* write directly if requested */ 91 if (state.state->direct) { 92 while (strm->avail_in) { 93 put = strm->avail_in > max ? max : strm->avail_in; 94 writ = (int)write(state.state->fd, strm->next_in, put); 95 if (writ < 0) { 96 gz_error(state, Z_ERRNO, zstrerror()); 97 return -1; 98 } 99 strm->avail_in -= (unsigned)writ; 100 strm->next_in += writ; 101 } 102 return 0; 103 } 104 105 /* run deflate() on provided input until it produces no more output */ 106 ret = Z_OK; 107 do { 108 /* write out current buffer contents if full, or if flushing, but if 109 doing Z_FINISH then don't write until we get to Z_STREAM_END */ 110 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && 111 (flush != Z_FINISH || ret == Z_STREAM_END))) { 112 while (strm->next_out > state.state->x.next) { 113 put = strm->next_out - state.state->x.next > (int)max ? max : 114 (unsigned)(strm->next_out - state.state->x.next); 115 writ = (int)write(state.state->fd, state.state->x.next, put); 116 if (writ < 0) { 117 gz_error(state, Z_ERRNO, zstrerror()); 118 return -1; 119 } 120 state.state->x.next += writ; 121 } 122 if (strm->avail_out == 0) { 123 strm->avail_out = state.state->size; 124 strm->next_out = state.state->out; 125 state.state->x.next = state.state->out; 126 } 127 } 128 129 /* compress */ 130 have = strm->avail_out; 131 ret = deflate(strm, flush); 132 if (ret == Z_STREAM_ERROR) { 133 gz_error(state, Z_STREAM_ERROR, 134 "internal error: deflate stream corrupt"); 135 return -1; 136 } 137 have -= strm->avail_out; 138 } while (have); 139 140 /* if that completed a deflate stream, allow another to start */ 141 if (flush == Z_FINISH) 142 deflateReset(strm); 143 144 /* all done, no errors */ 145 return 0; 146 } 147 148 /* Compress len zeros to output. Return -1 on a write error or memory 149 allocation failure by gz_comp(), or 0 on success. */ 150 local int gz_zero(state, len) 151 gz_statep state; 152 z_off64_t len; 153 { 154 int first; 155 unsigned n; 156 z_streamp strm = &(state.state->strm); 157 158 /* consume whatever's left in the input buffer */ 159 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 160 return -1; 161 162 /* compress len zeros (len guaranteed > 0) */ 163 first = 1; 164 while (len) { 165 n = GT_OFF(state.state->size) || (z_off64_t)state.state->size > len ? 166 (unsigned)len : state.state->size; 167 if (first) { 168 memset(state.state->in, 0, n); 169 first = 0; 170 } 171 strm->avail_in = n; 172 strm->next_in = state.state->in; 173 state.state->x.pos += n; 174 if (gz_comp(state, Z_NO_FLUSH) == -1) 175 return -1; 176 len -= n; 177 } 178 return 0; 179 } 180 181 /* Write len bytes from buf to file. Return the number of bytes written. If 182 the returned value is less than len, then there was an error. */ 183 local z_size_t gz_write(state, buf, len) 184 gz_statep state; 185 voidpc buf; 186 z_size_t len; 187 { 188 z_size_t put = len; 189 190 /* if len is zero, avoid unnecessary operations */ 191 if (len == 0) 192 return 0; 193 194 /* allocate memory if this is the first time through */ 195 if (state.state->size == 0 && gz_init(state) == -1) 196 return 0; 197 198 /* check for seek request */ 199 if (state.state->seek) { 200 state.state->seek = 0; 201 if (gz_zero(state, state.state->skip) == -1) 202 return 0; 203 } 204 205 /* for small len, copy to input buffer, otherwise compress directly */ 206 if (len < state.state->size) { 207 /* copy to input buffer, compress when full */ 208 do { 209 z_size_t have, copy; 210 211 if (state.state->strm.avail_in == 0) 212 state.state->strm.next_in = state.state->in; 213 have = (unsigned)((state.state->strm.next_in + state.state->strm.avail_in) - 214 state.state->in); 215 copy = state.state->size - have; 216 if (copy > len) 217 copy = len; 218 memcpy(state.state->in + have, buf, copy); 219 state.state->strm.avail_in += copy; 220 state.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 (state.state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 230 return 0; 231 232 /* directly compress user buffer to file */ 233 state.state->strm.next_in = (z_const Bytef *)buf; 234 do { 235 z_size_t n = (unsigned)-1; 236 if (n > len) 237 n = len; 238 state.state->strm.avail_in = (z_uInt)n; 239 state.state->x.pos += n; 240 if (gz_comp(state, Z_NO_FLUSH) == -1) 241 return 0; 242 len -= n; 243 } while (len); 244 } 245 246 /* input was all buffered or compressed */ 247 return put; 248 } 249 250 /* -- see zlib.h -- */ 251 int ZEXPORT gzwrite(file, buf, len) 252 gzFile file; 253 voidpc buf; 254 unsigned len; 255 { 256 gz_statep state; 257 258 /* get internal structure */ 259 if (file == NULL) 260 return 0; 261 state.file = file; 262 263 /* check that we're writing and that there's no error */ 264 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 265 return 0; 266 267 /* since an int is returned, make sure len fits in one, otherwise return 268 with an error (this avoids a flaw in the interface) */ 269 if ((int)len < 0) { 270 gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); 271 return 0; 272 } 273 274 /* write len bytes from buf (the return value will fit in an int) */ 275 return (int)gz_write(state, buf, len); 276 } 277 278 /* -- see zlib.h -- */ 279 z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) 280 voidpc buf; 281 z_size_t size; 282 z_size_t nitems; 283 gzFile file; 284 { 285 z_size_t len; 286 gz_statep state; 287 288 /* get internal structure */ 289 assert(size != 0); 290 if (file == NULL) 291 return 0; 292 state.file = file; 293 294 /* check that we're writing and that there's no error */ 295 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 296 return 0; 297 298 /* compute bytes to read -- error on overflow */ 299 len = nitems * size; 300 if (size && (len / size != nitems)) { 301 gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); 302 return 0; 303 } 304 305 /* write len bytes to buf, return the number of full items written */ 306 return len ? gz_write(state, buf, len) / size : 0; 307 } 308 309 /* -- see zlib.h -- */ 310 int ZEXPORT gzputc(file, c) 311 gzFile file; 312 int c; 313 { 314 unsigned have; 315 unsigned char buf[1]; 316 gz_statep state; 317 z_streamp strm; 318 319 /* get internal structure */ 320 if (file == NULL) 321 return -1; 322 state.file = file; 323 strm = &(state.state->strm); 324 325 /* check that we're writing and that there's no error */ 326 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 327 return -1; 328 329 /* check for seek request */ 330 if (state.state->seek) { 331 state.state->seek = 0; 332 if (gz_zero(state, state.state->skip) == -1) 333 return -1; 334 } 335 336 /* try writing to input buffer for speed (state.state->size == 0 if buffer not 337 initialized) */ 338 if (state.state->size) { 339 if (strm->avail_in == 0) 340 strm->next_in = state.state->in; 341 have = (unsigned)((strm->next_in + strm->avail_in) - state.state->in); 342 if (have < state.state->size) { 343 state.state->in[have] = (unsigned char)c; 344 strm->avail_in++; 345 state.state->x.pos++; 346 return c & 0xff; 347 } 348 } 349 350 /* no room in buffer or not initialized, use gz_write() */ 351 buf[0] = (unsigned char)c; 352 if (gz_write(state, buf, 1) != 1) 353 return -1; 354 return c & 0xff; 355 } 356 357 /* -- see zlib.h -- */ 358 int ZEXPORT gzputs(file, str) 359 gzFile file; 360 const char *str; 361 { 362 int ret; 363 z_size_t len; 364 gz_statep state; 365 366 /* get internal structure */ 367 if (file == NULL) 368 return -1; 369 state.file = file; 370 371 /* check that we're writing and that there's no error */ 372 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 373 return -1; 374 375 /* write string */ 376 len = strlen(str); 377 ret = (int)gz_write(state, str, len); 378 return ret == 0 && len != 0 ? -1 : ret; 379 } 380 381 #if defined(STDC) || defined(Z_HAVE_STDARG_H) 382 #include <stdarg.h> 383 384 /* -- see zlib.h -- */ 385 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) 386 { 387 int len; 388 unsigned left; 389 char *next; 390 gz_statep state; 391 z_streamp strm; 392 393 /* get internal structure */ 394 if (file == NULL) 395 return Z_STREAM_ERROR; 396 state.file = file; 397 strm = &(state.state->strm); 398 399 /* check that we're writing and that there's no error */ 400 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 401 return Z_STREAM_ERROR; 402 403 /* make sure we have some buffer space */ 404 if (state.state->size == 0 && gz_init(state) == -1) 405 return state.state->err; 406 407 /* check for seek request */ 408 if (state.state->seek) { 409 state.state->seek = 0; 410 if (gz_zero(state, state.state->skip) == -1) 411 return state.state->err; 412 } 413 414 /* do the printf() into the input buffer, put length in len -- the input 415 buffer is double-sized just for this function, so there is guaranteed to 416 be state.state->size bytes available after the current contents */ 417 if (strm->avail_in == 0) 418 strm->next_in = state.state->in; 419 next = (char *)(state.state->in + (strm->next_in - state.state->in) + strm->avail_in); 420 next[state.state->size - 1] = 0; 421 #ifdef NO_vsnprintf 422 # ifdef HAS_vsprintf_void 423 (void)vsprintf(next, format, va); 424 for (len = 0; len < state.state->size; len++) 425 if (next[len] == 0) break; 426 # else 427 len = vsprintf(next, format, va); 428 # endif 429 #else 430 # ifdef HAS_vsnprintf_void 431 (void)vsnprintf(next, state.state->size, format, va); 432 len = strlen(next); 433 # else 434 len = vsnprintf(next, state.state->size, format, va); 435 # endif 436 #endif 437 438 /* check that printf() results fit in buffer */ 439 if (len == 0 || (unsigned)len >= state.state->size || next[state.state->size - 1] != 0) 440 return 0; 441 442 /* update buffer and position, compress first half if past that */ 443 strm->avail_in += (unsigned)len; 444 state.state->x.pos += len; 445 if (strm->avail_in >= state.state->size) { 446 left = strm->avail_in - state.state->size; 447 strm->avail_in = state.state->size; 448 if (gz_comp(state, Z_NO_FLUSH) == -1) 449 return state.state->err; 450 memcpy(state.state->in, state.state->in + state.state->size, left); 451 strm->next_in = state.state->in; 452 strm->avail_in = left; 453 } 454 return len; 455 } 456 457 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) 458 { 459 va_list va; 460 int ret; 461 462 va_start(va, format); 463 ret = gzvprintf(file, format, va); 464 va_end(va); 465 return ret; 466 } 467 468 #else /* !STDC && !Z_HAVE_STDARG_H */ 469 470 /* -- see zlib.h -- */ 471 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 472 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 473 gzFile file; 474 const char *format; 475 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 476 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; 477 { 478 unsigned len, left; 479 char *next; 480 gz_statep state; 481 z_streamp strm; 482 483 /* get internal structure */ 484 if (file == NULL) 485 return Z_STREAM_ERROR; 486 state = (gz_statep)file; 487 strm = &(state.state->strm); 488 489 /* check that can really pass pointer in ints */ 490 if (sizeof(int) != sizeof(void *)) 491 return Z_STREAM_ERROR; 492 493 /* check that we're writing and that there's no error */ 494 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 495 return Z_STREAM_ERROR; 496 497 /* make sure we have some buffer space */ 498 if (state.state->size == 0 && gz_init(state) == -1) 499 return state.state->error; 500 501 /* check for seek request */ 502 if (state.state->seek) { 503 state.state->seek = 0; 504 if (gz_zero(state, state.state->skip) == -1) 505 return state.state->error; 506 } 507 508 /* do the printf() into the input buffer, put length in len -- the input 509 buffer is double-sized just for this function, so there is guaranteed to 510 be state.state->size bytes available after the current contents */ 511 if (strm->avail_in == 0) 512 strm->next_in = state.state->in; 513 next = (char *)(strm->next_in + strm->avail_in); 514 next[state.state->size - 1] = 0; 515 #ifdef NO_snprintf 516 # ifdef HAS_sprintf_void 517 sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, 518 a13, a14, a15, a16, a17, a18, a19, a20); 519 for (len = 0; len < size; len++) 520 if (next[len] == 0) 521 break; 522 # else 523 len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, 524 a12, a13, a14, a15, a16, a17, a18, a19, a20); 525 # endif 526 #else 527 # ifdef HAS_snprintf_void 528 snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, 529 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 530 len = strlen(next); 531 # else 532 len = snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, 533 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 534 # endif 535 #endif 536 537 /* check that printf() results fit in buffer */ 538 if (len == 0 || len >= state.state->size || next[state.state->size - 1] != 0) 539 return 0; 540 541 /* update buffer and position, compress first half if past that */ 542 strm->avail_in += len; 543 state.state->x.pos += len; 544 if (strm->avail_in >= state.state->size) { 545 left = strm->avail_in - state.state->size; 546 strm->avail_in = state.state->size; 547 if (gz_comp(state, Z_NO_FLUSH) == -1) 548 return state.state->err; 549 memcpy(state.state->in, state.state->in + state.state->size, left); 550 strm->next_in = state.state->in; 551 strm->avail_in = left; 552 } 553 return (int)len; 554 } 555 556 #endif 557 558 /* -- see zlib.h -- */ 559 int ZEXPORT gzflush(file, flush) 560 gzFile file; 561 int flush; 562 { 563 gz_statep state; 564 565 /* get internal structure */ 566 if (file == NULL) 567 return Z_STREAM_ERROR; 568 state.file = file; 569 570 /* check that we're writing and that there's no error */ 571 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 572 return Z_STREAM_ERROR; 573 574 /* check flush parameter */ 575 if (flush < 0 || flush > Z_FINISH) 576 return Z_STREAM_ERROR; 577 578 /* check for seek request */ 579 if (state.state->seek) { 580 state.state->seek = 0; 581 if (gz_zero(state, state.state->skip) == -1) 582 return state.state->err; 583 } 584 585 /* compress remaining data with requested flush */ 586 (void)gz_comp(state, flush); 587 return state.state->err; 588 } 589 590 /* -- see zlib.h -- */ 591 int ZEXPORT gzsetparams(file, level, strategy) 592 gzFile file; 593 int level; 594 int strategy; 595 { 596 gz_statep state; 597 z_streamp strm; 598 599 /* get internal structure */ 600 if (file == NULL) 601 return Z_STREAM_ERROR; 602 state.file = file; 603 strm = &(state.state->strm); 604 605 /* check that we're writing and that there's no error */ 606 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK) 607 return Z_STREAM_ERROR; 608 609 /* if no change is requested, then do nothing */ 610 if (level == state.state->level && strategy == state.state->strategy) 611 return Z_OK; 612 613 /* check for seek request */ 614 if (state.state->seek) { 615 state.state->seek = 0; 616 if (gz_zero(state, state.state->skip) == -1) 617 return state.state->err; 618 } 619 620 /* change compression parameters for subsequent input */ 621 if (state.state->size) { 622 /* flush previous input with previous parameters before changing */ 623 if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) 624 return state.state->err; 625 deflateParams(strm, level, strategy); 626 } 627 state.state->level = level; 628 state.state->strategy = strategy; 629 return Z_OK; 630 } 631 632 /* -- see zlib.h -- */ 633 int ZEXPORT gzclose_w(file) 634 gzFile file; 635 { 636 int ret = Z_OK; 637 gz_statep state; 638 639 /* get internal structure */ 640 if (file == NULL) 641 return Z_STREAM_ERROR; 642 state.file = file; 643 644 /* check that we're writing */ 645 if (state.state->mode != GZ_WRITE) 646 return Z_STREAM_ERROR; 647 648 /* check for seek request */ 649 if (state.state->seek) { 650 state.state->seek = 0; 651 if (gz_zero(state, state.state->skip) == -1) 652 ret = state.state->err; 653 } 654 655 /* flush, free memory, and close file */ 656 if (gz_comp(state, Z_FINISH) == -1) 657 ret = state.state->err; 658 if (state.state->size) { 659 if (!state.state->direct) { 660 (void)deflateEnd(&(state.state->strm)); 661 free(state.state->out); 662 } 663 free(state.state->in); 664 } 665 gz_error(state, Z_OK, NULL); 666 free(state.state->path); 667 if (close(state.state->fd) == -1) 668 ret = Z_ERRNO; 669 free(state.state); 670 return ret; 671 } 672