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