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