apps/ccam/gzio_compress.c

Go to the documentation of this file.
00001 /* gzio_compress.c -- IO on .gz files
00002  * Copyright (C) 1995-2002 Jean-loup Gailly.
00003  * For conditions of distribution and use, see copyright notice in zlib.h
00004  *
00005  * Compile this file with -DNO_DEFLATE to avoid the compression code.
00006  */
00007 
00008 /* @(#) $Id: gzio_compress.c,v 1.1.1.1 2007/06/25 18:20:19 elphel Exp $ */
00009 
00010 #include <stdio.h>
00011 
00012 #include "zlib/zutil.h"
00013 #include "gzio_compress.h"
00014 
00015 struct internal_state {int dummy;}; /* for buggy compilers */
00016 
00017 #ifndef Z_BUFSIZE
00018 #  ifdef MAXSEG_64K
00019 #    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
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}; /* gzip magic header */
00032 
00033 /* gzip flag byte */
00034 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
00035 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
00036 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
00037 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
00038 #define COMMENT      0x10 /* bit 4 set: file comment present */
00039 #define RESERVED     0xE0 /* bits 5..7: reserved */
00040 
00041 typedef struct gz_stream {
00042     z_stream stream;
00043     int      z_err;   /* error code for last stream operation */
00044     int      z_eof;   /* set if end of input file */
00045     FILE     *file;   /* .gz file */
00046     Byte     *inbuf;  /* input buffer */
00047     Byte     *outbuf; /* output buffer */
00048     uLong    crc;     /* crc32 of uncompressed data */
00049     char     *msg;    /* error message */
00050     char     *path;   /* path name for debugging only */
00051     int      transparent; /* 1 if input file is not a .gz file */
00052     char     mode;    /* 'w' or 'r' */
00053     long     startpos; /* start of compressed data in file (header skipped) */
00054 } gz_stream;
00055 
00056 gzFile gz_useFile (FILE *file, const char *mode); // compressor mode only
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      Opens a gzip (.gz) file for reading or writing. The mode parameter
00065    is as in fopen ("rb" or "wb"). The file is given either by file descriptor
00066    or path name (if fd == -1).
00067      gz_open return NULL if the file could not be opened or if there was
00068    insufficient memory to allocate the (de)compression state; errno
00069    can be checked to distinguish the two cases (if errno is zero, the
00070    zlib error is Z_MEM_ERROR).
00071 */
00072 gzFile gz_useFile (file,mode) // compressor mode only
00073     FILE *file;
00074     const char *mode;
00075 {
00076     int err;
00077     int level = Z_DEFAULT_COMPRESSION; /* compression level */
00078     int strategy = Z_DEFAULT_STRATEGY; /* compression 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; // to speedup gzprintf
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           /* windowBits is passed < 0 to suppress zlib header */
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) { // no header if level=0 !!!
00143         /* Write a very simple .gz header:
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 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
00147         s->startpos = 10L;
00148         /* We use 10L instead of ftell(s->file) to because ftell causes an
00149          * fflush on some systems. This version of the library doesn't use
00150          * startpos anyway in write mode, so this initialization is not
00151          * necessary.
00152          */
00153     }
00154     return (gzFile)s;
00155 }
00156 
00157 
00158  /* ===========================================================================
00159  * Cleanup then free the given gz_stream. Return a zlib error code.
00160    Try freeing in the reverse order of allocations.
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) /* fclose is broken for pipes in HP/UX */
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      Writes the given number of uncompressed bytes into the compressed file.
00198    gzwrite returns the number of bytes actually written (0 in case of error).
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      Converts, formats, and writes the args to the compressed file under
00233    control of the format string, as in fprintf. gzprintf returns the number of
00234    uncompressed bytes actually written (0 in case of error).
00235 */
00236 #ifdef STDC
00237 #include <stdarg.h>
00238 
00239 int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
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     if (s->transparent) { // speedup non-compressed mode
00249       len=fprintf(s->file, format, va);
00250       va_end(va);
00251       return len;
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); /* some *sprintf don't return the nb of bytes written */
00261     if (len <= 0) return 0;
00262     if (s->transparent) { // speedup non-compressed mode
00263       return fwrite(buf, (size_t) len, 1, s->file);
00264     }
00265 
00266     return gzwrite(file, buf, (unsigned)len);
00267 }
00268 #else /* not ANSI C */
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); /* old sprintf doesn't return the nb of bytes written */
00288     if (len <= 0) return 0;
00289 
00290     return gzwrite(file, buf, len);
00291 }
00292 #endif
00293 
00294 /* ===========================================================================
00295      Flushes all pending output into the compressed file. The parameter
00296    flush is as in the deflate() function.
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; /* should be zero already anyway */
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         /* Ignore the second of two consecutive flushes: */
00325         if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
00326 
00327         /* deflate has finished flushing only when it hasn't used up
00328          * all the available space in the output buffer: 
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 /* NO_DEFLATE */
00338 
00339 /* ===========================================================================
00340       Sets the starting position for the next gzread or gzwrite on the given
00341    compressed file. The offset represents a number of bytes in the
00342       gzseek returns the resulting offset location as measured in bytes from
00343    the beginning of the uncompressed stream, or -1 in case of error.
00344       SEEK_END is not implemented, returns error.
00345       In this version of the library, gzseek can be extremely slow.
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         /* At this point, offset is the number of zero bytes to write. */
00369         if (s->inbuf == Z_NULL) {
00370             s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
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      Returns the starting position for the next gzread or gzwrite on the
00391    given compressed file. This position represents a number of bytes in the
00392    uncompressed data stream.
00393 */
00394 z_off_t ZEXPORT gztell (file)
00395     gzFile file;
00396 {
00397     return gzseek(file, 0L, SEEK_CUR);
00398 }
00399 
00400 /* ===========================================================================
00401      Returns 1 when EOF has previously been detected reading the given
00402    input stream, otherwise zero.
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    Outputs a long in LSB order to the given file
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      Flushes all pending output if necessary, closes the compressed file
00429    and deallocates all the (de)compression state.
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) {// no header/trailer in transparent mode !!!
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      Returns the error message for the last error which occured on the
00456    given compressed file. errnum is set to zlib error number. If an
00457    error occured in the file system and not in the compression library,
00458    errnum is set to Z_ERRNO and the application may consult errno
00459    to get the exact error code.
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 }

Generated on Thu Aug 7 16:18:59 2008 for elphel by  doxygen 1.5.1