00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011
00012 #include "zlib/zutil.h"
00013 #include "gzio_compress.h"
00014
00015 struct internal_state {int dummy;};
00016
00017 #ifndef Z_BUFSIZE
00018 # ifdef MAXSEG_64K
00019 # define Z_BUFSIZE 4096
00020 # else
00021 # define Z_BUFSIZE 16384
00022 # endif
00023 #endif
00024 #ifndef Z_PRINTF_BUFSIZE
00025 # define Z_PRINTF_BUFSIZE 4096
00026 #endif
00027
00028 #define ALLOC(size) malloc(size)
00029 #define TRYFREE(p) {if (p) free(p);}
00030
00031 static int gz_magic[2] = {0x1f, 0x8b};
00032
00033
00034 #define ASCII_FLAG 0x01
00035 #define HEAD_CRC 0x02
00036 #define EXTRA_FIELD 0x04
00037 #define ORIG_NAME 0x08
00038 #define COMMENT 0x10
00039 #define RESERVED 0xE0
00040
00041 typedef struct gz_stream {
00042 z_stream stream;
00043 int z_err;
00044 int z_eof;
00045 FILE *file;
00046 Byte *inbuf;
00047 Byte *outbuf;
00048 uLong crc;
00049 char *msg;
00050 char *path;
00051 int transparent;
00052 char mode;
00053 long startpos;
00054 } gz_stream;
00055
00056 gzFile gz_useFile (FILE *file, const char *mode);
00057
00058 local gzFile gz_open OF((const char *path, const char *mode, int fd));
00059 local int do_flush OF((gzFile file, int flush));
00060 local int destroy OF((gz_stream *s));
00061 local void putLong OF((FILE *file, uLong x));
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 gzFile gz_useFile (file,mode)
00073 FILE *file;
00074 const char *mode;
00075 {
00076 int err;
00077 int level = Z_DEFAULT_COMPRESSION;
00078 int strategy = Z_DEFAULT_STRATEGY;
00079 char *p = (char*)mode;
00080 gz_stream *s;
00081 if (!mode) return Z_NULL;
00082
00083 s = (gz_stream *)ALLOC(sizeof(gz_stream));
00084 if (!s) return Z_NULL;
00085 s->startpos = 0L;
00086 s->stream.zalloc = (alloc_func)0;
00087 s->stream.zfree = (free_func)0;
00088 s->stream.opaque = (voidpf)0;
00089 s->stream.next_in = s->inbuf = Z_NULL;
00090 s->stream.next_out = s->outbuf = Z_NULL;
00091 s->stream.avail_in = s->stream.avail_out = 0;
00092 s->file = file;
00093 s->z_err = Z_OK;
00094 s->z_eof = 0;
00095 s->crc = crc32(0L, Z_NULL, 0);
00096 s->msg = NULL;
00097 s->transparent = 0;
00098
00099 s->path = NULL;
00100
00101 s->mode = '\0';
00102 do {
00103 if (*p == 'r') s->mode = 'r';
00104 if (*p == 'w' || *p == 'a') s->mode = 'w';
00105 if (*p >= '0' && *p <= '9') {
00106 level = *p - '0';
00107 } else if (*p == 'f') {
00108 strategy = Z_FILTERED;
00109 } else if (*p == 'h') {
00110 strategy = Z_HUFFMAN_ONLY;
00111 }
00112 } while (*p++);
00113 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
00114
00115 if (s->mode == 'w') {
00116 if (level==0) s->transparent = 1;
00117
00118 #ifdef NO_DEFLATE
00119 err = Z_STREAM_ERROR;
00120 #else
00121 if (!s->transparent) {
00122 err = deflateInit2(&(s->stream), level,
00123 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
00124
00125
00126 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
00127 #endif
00128 if (err != Z_OK || s->outbuf == Z_NULL) {
00129 return destroy(s), (gzFile)Z_NULL;
00130 }
00131 }
00132 } else {
00133 err = Z_STREAM_ERROR;
00134 return destroy(s), (gzFile)Z_NULL;
00135 }
00136 s->stream.avail_out = Z_BUFSIZE;
00137
00138 errno = 0;
00139 if (s->file == NULL) {
00140 return destroy(s), (gzFile)Z_NULL;
00141 }
00142 if ((s->mode == 'w') && !s->transparent) {
00143
00144
00145 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
00146 Z_DEFLATED, 0 , 0,0,0,0 , 0 , OS_CODE);
00147 s->startpos = 10L;
00148
00149
00150
00151
00152
00153 }
00154 return (gzFile)s;
00155 }
00156
00157
00158
00159
00160
00161
00162 local int destroy (s)
00163 gz_stream *s;
00164 {
00165 int err = Z_OK;
00166
00167 if (!s) return Z_STREAM_ERROR;
00168
00169 TRYFREE(s->msg);
00170
00171 if (s->stream.state != NULL) {
00172 if (s->mode == 'w') {
00173 #ifdef NO_DEFLATE
00174 err = Z_STREAM_ERROR;
00175 #else
00176 err = deflateEnd(&(s->stream));
00177 #endif
00178 }
00179 }
00180 if (s->file != NULL && fclose(s->file)) {
00181 #ifdef ESPIPE
00182 if (errno != ESPIPE)
00183 #endif
00184 err = Z_ERRNO;
00185 }
00186 if (s->z_err < 0) err = s->z_err;
00187
00188 TRYFREE(s->inbuf);
00189 TRYFREE(s->outbuf);
00190 TRYFREE(s->path);
00191 TRYFREE(s);
00192 return err;
00193 }
00194
00195 #ifndef NO_DEFLATE
00196
00197
00198
00199
00200 int ZEXPORT gzwrite (file, buf, len)
00201 gzFile file;
00202 const voidp buf;
00203 unsigned len;
00204 {
00205 gz_stream *s = (gz_stream*)file;
00206
00207 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
00208
00209 s->stream.next_in = (Bytef*)buf;
00210 s->stream.avail_in = len;
00211
00212 while (s->stream.avail_in != 0) {
00213
00214 if (s->stream.avail_out == 0) {
00215
00216 s->stream.next_out = s->outbuf;
00217 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
00218 s->z_err = Z_ERRNO;
00219 break;
00220 }
00221 s->stream.avail_out = Z_BUFSIZE;
00222 }
00223 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
00224 if (s->z_err != Z_OK) break;
00225 }
00226 s->crc = crc32(s->crc, (const Bytef *)buf, len);
00227
00228 return (int)(len - s->stream.avail_in);
00229 }
00230
00231
00232
00233
00234
00235
00236 #ifdef STDC
00237 #include <stdarg.h>
00238
00239 int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
00240 {
00241 gz_stream *s = (gz_stream*)file;
00242 char buf[Z_PRINTF_BUFSIZE];
00243 va_list va;
00244 int len;
00245
00246 va_start(va, format);
00247
00248
00249
00250
00251
00252
00253
00254 #ifdef HAS_vsnprintf
00255 (void)vsnprintf(buf, sizeof(buf), format, va);
00256 #else
00257 (void)vsprintf(buf, format, va);
00258 #endif
00259 va_end(va);
00260 len = strlen(buf);
00261 if (len <= 0) return 0;
00262 if (s->transparent) {
00263 return fwrite(buf, (size_t) len, 1, s->file);
00264 }
00265
00266 return gzwrite(file, buf, (unsigned)len);
00267 }
00268 #else
00269 #error not ANSI C!
00270 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
00271 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
00272 gzFile file;
00273 const char *format;
00274 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
00275 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
00276 {
00277 char buf[Z_PRINTF_BUFSIZE];
00278 int len;
00279
00280 #ifdef HAS_snprintf
00281 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
00282 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00283 #else
00284 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
00285 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
00286 #endif
00287 len = strlen(buf);
00288 if (len <= 0) return 0;
00289
00290 return gzwrite(file, buf, len);
00291 }
00292 #endif
00293
00294
00295
00296
00297
00298 local int do_flush (file, flush)
00299 gzFile file;
00300 int flush;
00301 {
00302 uInt len;
00303 int done = 0;
00304 gz_stream *s = (gz_stream*)file;
00305
00306 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
00307
00308 s->stream.avail_in = 0;
00309
00310 for (;;) {
00311 len = Z_BUFSIZE - s->stream.avail_out;
00312
00313 if (len != 0) {
00314 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
00315 s->z_err = Z_ERRNO;
00316 return Z_ERRNO;
00317 }
00318 s->stream.next_out = s->outbuf;
00319 s->stream.avail_out = Z_BUFSIZE;
00320 }
00321 if (done) break;
00322 s->z_err = deflate(&(s->stream), flush);
00323
00324
00325 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
00326
00327
00328
00329
00330 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
00331
00332 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
00333 }
00334 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
00335 }
00336
00337 #endif
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 z_off_t ZEXPORT gzseek (file, offset, whence)
00348 gzFile file;
00349 z_off_t offset;
00350 int whence;
00351 {
00352 gz_stream *s = (gz_stream*)file;
00353
00354 if (s == NULL || whence == SEEK_END ||
00355 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
00356 return -1L;
00357 }
00358
00359 if (s->mode == 'w') {
00360 #ifdef NO_DEFLATE
00361 return -1L;
00362 #else
00363 if (whence == SEEK_SET) {
00364 offset -= s->stream.total_in;
00365 }
00366 if (offset < 0) return -1L;
00367
00368
00369 if (s->inbuf == Z_NULL) {
00370 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
00371 zmemzero(s->inbuf, Z_BUFSIZE);
00372 }
00373 while (offset > 0) {
00374 uInt size = Z_BUFSIZE;
00375 if (offset < Z_BUFSIZE) size = (uInt)offset;
00376
00377 size = gzwrite(file, s->inbuf, size);
00378 if (size == 0) return -1L;
00379
00380 offset -= size;
00381 }
00382 return (z_off_t)s->stream.total_in;
00383 #endif
00384 }
00385 return 0;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394 z_off_t ZEXPORT gztell (file)
00395 gzFile file;
00396 {
00397 return gzseek(file, 0L, SEEK_CUR);
00398 }
00399
00400
00401
00402
00403
00404 int ZEXPORT gzeof (file)
00405 gzFile file;
00406 {
00407 gz_stream *s = (gz_stream*)file;
00408
00409 return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
00410 }
00411
00412
00413
00414
00415 local void putLong (file, x)
00416 FILE *file;
00417 uLong x;
00418 {
00419 int n;
00420 for (n = 0; n < 4; n++) {
00421 fputc((int)(x & 0xff), file);
00422 x >>= 8;
00423 }
00424 }
00425
00426
00427
00428
00429
00430
00431 int ZEXPORT gzclose (file)
00432 gzFile file;
00433 {
00434 int err;
00435 gz_stream *s = (gz_stream*)file;
00436
00437 if (s == NULL) return Z_STREAM_ERROR;
00438
00439 if (s->mode == 'w') {
00440 #ifdef NO_DEFLATE
00441 return Z_STREAM_ERROR;
00442 #else
00443 if (!s->transparent) {
00444 err = do_flush (file, Z_FINISH);
00445 if (err != Z_OK) return destroy((gz_stream*)file);
00446 putLong (s->file, s->crc);
00447 putLong (s->file, s->stream.total_in);
00448 }
00449 #endif
00450 }
00451 return destroy((gz_stream*)file);
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461 const char* ZEXPORT gzerror (file, errnum)
00462 gzFile file;
00463 int *errnum;
00464 {
00465 char *m;
00466 gz_stream *s = (gz_stream*)file;
00467
00468 if (s == NULL) {
00469 *errnum = Z_STREAM_ERROR;
00470 return (const char*)ERR_MSG(Z_STREAM_ERROR);
00471 }
00472 *errnum = s->z_err;
00473 if (*errnum == Z_OK) return (const char*)"";
00474
00475 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
00476
00477 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
00478
00479 TRYFREE(s->msg);
00480 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
00481 strcpy(s->msg, s->path);
00482 strcat(s->msg, ": ");
00483 strcat(s->msg, m);
00484 return (const char*)s->msg;
00485 }