gzip: new GZIP_BIG_MEM option
[oweals/busybox.git] / archival / gzip.c
index ee051356e5100832769bcb0c752ec0302cb1bf7a..0e0b681424e595837d552df974f148c85760e392 100644 (file)
@@ -13,7 +13,7 @@
  * files as well as stdin/stdout, and to generally behave itself wrt
  * command line handling.
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
 /* big objects in bss:
@@ -39,7 +39,23 @@ gzip: bogus: No such file or directory
 aa:      85.1% -- replaced with aa.gz
 */
 
+//usage:#define gzip_trivial_usage
+//usage:       "[-cfd] [FILE]..."
+//usage:#define gzip_full_usage "\n\n"
+//usage:       "Compress FILEs (or stdin)\n"
+//usage:     "\n       -d      Decompress"
+//usage:     "\n       -c      Write to stdout"
+//usage:     "\n       -f      Force"
+//usage:
+//usage:#define gzip_example_usage
+//usage:       "$ ls -la /tmp/busybox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/busybox.tar\n"
+//usage:       "$ gzip /tmp/busybox.tar\n"
+//usage:       "$ ls -la /tmp/busybox*\n"
+//usage:       "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
+
 #include "libbb.h"
+#include "archive.h"
 
 
 /* ===========================================================================
@@ -65,9 +81,13 @@ aa:      85.1% -- replaced with aa.gz
 
 /* ===========================================================================
  */
-#define SMALL_MEM
+#if ENABLE_GZIP_BIG_MEM
+# define BIG_MEM
+#else
+# define SMALL_MEM
+#endif
 
-#ifndef        INBUFSIZ
+#ifndef INBUFSIZ
 #  ifdef SMALL_MEM
 #    define INBUFSIZ  0x2000   /* input buffer size */
 #  else
@@ -75,7 +95,7 @@ aa:      85.1% -- replaced with aa.gz
 #  endif
 #endif
 
-#ifndef        OUTBUFSIZ
+#ifndef OUTBUFSIZ
 #  ifdef SMALL_MEM
 #    define OUTBUFSIZ   8192   /* output buffer size */
 #  else
@@ -266,7 +286,7 @@ struct globals {
 #define DECLARE(type, array, size) \
        type * array
 #define ALLOC(type, array, size) \
-       array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type));
+       array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type))
 #define FREE(array) \
        do { free(array); array = NULL; } while (0)
 
@@ -339,7 +359,7 @@ struct globals {
        ulg bits_sent;                  /* bit length of the compressed data */
 #endif
 
-       uint32_t *crc_32_tab;
+       /*uint32_t *crc_32_tab;*/
        uint32_t crc;   /* shift register contents */
 };
 
@@ -387,33 +407,14 @@ static void put_32bit(ulg n)
        put_16bit(n >> 16);
 }
 
-/* ===========================================================================
- * Clear input and output buffers
- */
-static void clear_bufs(void)
-{
-       G1.outcnt = 0;
-#ifdef DEBUG
-       G1.insize = 0;
-#endif
-       G1.isize = 0;
-}
-
-
 /* ===========================================================================
  * Run a set of bytes through the crc shift register.  If s is a NULL
  * pointer, then initialize the crc shift register contents instead.
  * Return the current crc in either case.
  */
-static uint32_t updcrc(uch * s, unsigned n)
+static void updcrc(uch * s, unsigned n)
 {
-       uint32_t c = G1.crc;
-       while (n) {
-               c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8);
-               n--;
-       }
-       G1.crc = c;
-       return c;
+       G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/);
 }
 
 
@@ -632,10 +633,12 @@ static int longest_match(IPos cur_match)
                /* Skip to next match if the match length cannot increase
                 * or if the match length is less than 2:
                 */
-               if (match[best_len] != scan_end ||
-                       match[best_len - 1] != scan_end1 ||
-                       *match != *scan || *++match != scan[1])
+               if (match[best_len] != scan_end
+                || match[best_len - 1] != scan_end1
+                || *match != *scan || *++match != scan[1]
+               ) {
                        continue;
+               }
 
                /* The check at best_len-1 can be removed because it will be made
                 * again later. (This heuristic is not always a win.)
@@ -686,7 +689,7 @@ static void check_match(IPos start, IPos match, int length)
        if (verbose > 1) {
                bb_error_msg("\\[%d,%d]", start - match, length);
                do {
-                       fputc(G1.window[start++], stderr);
+                       bb_putchar_stderr(G1.window[start++]);
                } while (--length != 0);
        }
 }
@@ -974,7 +977,7 @@ static void compress_block(ct_data * ltree, ct_data * dtree);
 #else
 #  define SEND_CODE(c, tree) \
 { \
-       if (verbose > 1) bb_error_msg("\ncd %3d ",(c)); \
+       if (verbose > 1) bb_error_msg("\ncd %3d ", (c)); \
        send_bits(tree[c].Code, tree[c].Len); \
 }
 #endif
@@ -1185,7 +1188,7 @@ static void gen_codes(ct_data * tree, int max_code)
 
                Tracec(tree != G2.static_ltree,
                           (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
-                               (isgraph(n) ? n : ' '), len, tree[n].Code,
+                               (n > ' ' ? n : ' '), len, tree[n].Code,
                                next_code[len] - 1));
        }
 }
@@ -1553,7 +1556,7 @@ static void compress_block(ct_data * ltree, ct_data * dtree)
                lc = G1.l_buf[lx++];
                if ((flag & 1) == 0) {
                        SEND_CODE(lc, ltree);   /* send a literal byte */
-                       Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
+                       Tracecv(lc > ' ', (stderr, " '%c' ", lc));
                } else {
                        /* Here, lc is the match length - MIN_MATCH */
                        code = G2.length_code[lc];
@@ -1674,7 +1677,7 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
 
 /* ===========================================================================
  * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ * IN  assertion: all calls to UPDATE_HASH are made with consecutive
  *    input characters, so that a running hash key can be computed from the
  *    previous key instead of complete recalculation each time.
  */
@@ -1705,7 +1708,7 @@ static ulg flush_block(char *buf, ulg stored_len, int eof)
 /* Insert string s in the dictionary and set match_head to the previous head
  * of the hash chain (the most recent string with same hash key). Return
  * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ * IN  assertion: all calls to INSERT_STRING are made with consecutive
  *    input characters and the first MIN_MATCH bytes of s are valid
  *    (except for the last MIN_MATCH-1 bytes of the input file). */
 #define INSERT_STRING(s, match_head) \
@@ -2008,25 +2011,66 @@ static void zip(ulg time_stamp)
 
 /* ======================================================================== */
 static
-char* make_new_name_gzip(char *filename)
-{
-       return xasprintf("%s.gz", filename);
-}
-
-static
-USE_DESKTOP(long long) int pack_gzip(void)
+IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM)
 {
        struct stat s;
 
-       clear_bufs();
+       /* Clear input and output buffers */
+       G1.outcnt = 0;
+#ifdef DEBUG
+       G1.insize = 0;
+#endif
+       G1.isize = 0;
+
+       /* Reinit G2.xxx */
+       memset(&G2, 0, sizeof(G2));
+       G2.l_desc.dyn_tree     = G2.dyn_ltree;
+       G2.l_desc.static_tree  = G2.static_ltree;
+       G2.l_desc.extra_bits   = extra_lbits;
+       G2.l_desc.extra_base   = LITERALS + 1;
+       G2.l_desc.elems        = L_CODES;
+       G2.l_desc.max_length   = MAX_BITS;
+       //G2.l_desc.max_code     = 0;
+       G2.d_desc.dyn_tree     = G2.dyn_dtree;
+       G2.d_desc.static_tree  = G2.static_dtree;
+       G2.d_desc.extra_bits   = extra_dbits;
+       //G2.d_desc.extra_base   = 0;
+       G2.d_desc.elems        = D_CODES;
+       G2.d_desc.max_length   = MAX_BITS;
+       //G2.d_desc.max_code     = 0;
+       G2.bl_desc.dyn_tree    = G2.bl_tree;
+       //G2.bl_desc.static_tree = NULL;
+       G2.bl_desc.extra_bits  = extra_blbits,
+       //G2.bl_desc.extra_base  = 0;
+       G2.bl_desc.elems       = BL_CODES;
+       G2.bl_desc.max_length  = MAX_BL_BITS;
+       //G2.bl_desc.max_code    = 0;
+
        s.st_ctime = 0;
        fstat(STDIN_FILENO, &s);
        zip(s.st_ctime);
        return 0;
 }
 
+#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
+static const char gzip_longopts[] ALIGN1 =
+       "stdout\0"              No_argument       "c"
+       "to-stdout\0"           No_argument       "c"
+       "force\0"               No_argument       "f"
+       "verbose\0"             No_argument       "v"
+#if ENABLE_GUNZIP
+       "decompress\0"          No_argument       "d"
+       "uncompress\0"          No_argument       "d"
+       "test\0"                No_argument       "t"
+#endif
+       "quiet\0"               No_argument       "q"
+       "fast\0"                No_argument       "1"
+       "best\0"                No_argument       "9"
+       ;
+#endif
+
 /*
- * Linux kernel build uses gzip -d -n. We accept and ignore it.
+ * Linux kernel build uses gzip -d -n. We accept and ignore -n.
  * Man page says:
  * -n --no-name
  * gzip: do not save the original file name and time stamp.
@@ -2048,8 +2092,11 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
 {
        unsigned opt;
 
+#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
+       applet_long_options = gzip_longopts;
+#endif
        /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
-       opt = getopt32(argv, "cfv" USE_GUNZIP("dt") "q123456789n");
+       opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "q123456789n");
 #if ENABLE_GUNZIP /* gunzip_main may not be visible... */
        if (opt & 0x18) // -d and/or -t
                return gunzip_main(argc, argv);
@@ -2060,32 +2107,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
        //if (opt & 0x4) // -v
        argv += optind;
 
-       SET_PTR_TO_GLOBALS(xzalloc(sizeof(struct globals) + sizeof(struct globals2))
+       SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2))
                        + sizeof(struct globals));
-       barrier();
-       G2.l_desc.dyn_tree    = G2.dyn_ltree;
-       G2.l_desc.static_tree = G2.static_ltree;
-       G2.l_desc.extra_bits  = extra_lbits;
-       G2.l_desc.extra_base  = LITERALS + 1;
-       G2.l_desc.elems       = L_CODES;
-       G2.l_desc.max_length  = MAX_BITS;
-       //G2.l_desc.max_code    = 0;
-
-       G2.d_desc.dyn_tree    = G2.dyn_dtree;
-       G2.d_desc.static_tree = G2.static_dtree;
-       G2.d_desc.extra_bits  = extra_dbits;
-       //G2.d_desc.extra_base  = 0;
-       G2.d_desc.elems       = D_CODES;
-       G2.d_desc.max_length  = MAX_BITS;
-       //G2.d_desc.max_code    = 0;
-
-       G2.bl_desc.dyn_tree    = G2.bl_tree;
-       //G2.bl_desc.static_tree = NULL;
-       G2.bl_desc.extra_bits  = extra_blbits,
-       //G2.bl_desc.extra_base  = 0;
-       G2.bl_desc.elems       = BL_CODES;
-       G2.bl_desc.max_length  = MAX_BL_BITS;
-       //G2.bl_desc.max_code    = 0;
 
        /* Allocate all global buffers (for DYN_ALLOC option) */
        ALLOC(uch, G1.l_buf, INBUFSIZ);
@@ -2094,8 +2117,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv)
        ALLOC(uch, G1.window, 2L * WSIZE);
        ALLOC(ush, G1.prev, 1L << BITS);
 
-       /* Initialise the CRC32 table */
-       G1.crc_32_tab = crc32_filltable(NULL, 0);
+       /* Initialize the CRC32 table */
+       global_crc32_table = crc32_filltable(NULL, 0);
 
-       return bbunpack(argv, make_new_name_gzip, pack_gzip);
+       return bbunpack(argv, pack_gzip, append_ext, "gz");
 }