19e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* gzappend -- command to append to a gzip file
29e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
304351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes  Copyright (C) 2003, 2012 Mark Adler, all rights reserved
404351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes  version 1.2, 11 Oct 2012
59e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
69e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  This software is provided 'as-is', without any express or implied
79e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  warranty.  In no event will the author be held liable for any damages
89e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  arising from the use of this software.
99e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  Permission is granted to anyone to use this software for any purpose,
119e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  including commercial applications, and to alter it and redistribute it
129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  freely, subject to the following restrictions:
139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  1. The origin of this software must not be misrepresented; you must not
159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project     claim that you wrote the original software. If you use this software
169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project     in a product, an acknowledgment in the product documentation would be
179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project     appreciated but is not required.
189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  2. Altered source versions must be plainly marked as such, and must not be
199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project     misrepresented as being the original software.
209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  3. This notice may not be removed or altered from any source distribution.
219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project  Mark Adler    madler@alumni.caltech.edu
239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project */
249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/*
269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project * Change history:
279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *
289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project * 1.0  19 Oct 2003     - First version
299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project * 1.1   4 Nov 2003     - Expand and clarify some comments and notes
309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Add version and copyright to help
319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Send help to stdout instead of stderr
329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Add some preemptive typecasts
339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Add L to constants in lseek() calls
349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Remove some debugging information in error messages
359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Use new data_type definition for zlib 1.2.1
369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Simplfy and unify file operations
379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Finish off gzip file in gztack()
389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Use deflatePrime() instead of adding empty blocks
399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Keep gzip file clean on appended file read errors
409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                      - Use in-place rotate instead of auxiliary buffer
419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project *                        (Why you ask?  Because it was fun to write!)
4204351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes * 1.2  11 Oct 2012     - Fix for proper z_const usage
4304351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes *                      - Check for input buffer malloc failure
449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project */
459e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
469e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/*
479e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   gzappend takes a gzip file and appends to it, compressing files from the
489e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   command line or data from stdin.  The gzip file is written to directly, to
499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   avoid copying that file, in case it's large.  Note that this results in the
509e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   unfriendly behavior that if gzappend fails, the gzip file is corrupted.
519e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   This program was written to illustrate the use of the new Z_BLOCK option of
539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   zlib 1.2.x's inflate() function.  This option returns from inflate() at each
549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   block boundary to facilitate locating and modifying the last block bit at
559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   the start of the final deflate block.  Also whether using Z_BLOCK or not,
569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   another required feature of zlib 1.2.x is that inflate() now provides the
579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   number of unusued bits in the last input byte used.  gzappend will not work
589e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   with versions of zlib earlier than 1.2.1.
599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
609e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   gzappend first decompresses the gzip file internally, discarding all but
619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   the last 32K of uncompressed data, and noting the location of the last block
629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   bit and the number of unused bits in the last byte of the compressed data.
639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   The gzip trailer containing the CRC-32 and length of the uncompressed data
649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   is verified.  This trailer will be later overwritten.
659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   Then the last block bit is cleared by seeking back in the file and rewriting
679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   the byte that contains it.  Seeking forward, the last byte of the compressed
689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   data is saved along with the number of unused bits to initialize deflate.
699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   A deflate process is initialized, using the last 32K of the uncompressed
719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   data from the gzip file to initialize the dictionary.  If the total
729e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   uncompressed data was less than 32K, then all of it is used to initialize
739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   the dictionary.  The deflate output bit buffer is also initialized with the
749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   last bits from the original deflate stream.  From here on, the data to
759e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   append is simply compressed using deflate, and written to the gzip file.
769e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   When that is complete, the new CRC-32 and uncompressed length are written
779e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   as the trailer of the gzip file.
789e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project */
799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include <stdio.h>
819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include <stdlib.h>
829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include <string.h>
839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include <fcntl.h>
849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include <unistd.h>
859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#include "zlib.h"
869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define local static
889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define LGCHUNK 14
899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define CHUNK (1U << LGCHUNK)
909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define DSIZE 32768U
919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* print an error message and terminate with extreme prejudice */
939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal void bye(char *msg1, char *msg2)
949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2);
969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    exit(1);
979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* return the greatest common divisor of a and b using Euclid's algorithm,
1009e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   modified to be fast when one argument much greater than the other, and
1019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   coded to avoid unnecessary swapping */
1029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal unsigned gcd(unsigned a, unsigned b)
1039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
1049e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned c;
1059e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1069e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    while (a && b)
1079e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (a > b) {
1089e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            c = b;
1099e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            while (a - c >= c)
1109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                c <<= 1;
1119e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            a -= c;
1129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
1139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        else {
1149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            c = a;
1159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            while (b - c >= c)
1169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                c <<= 1;
1179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            b -= c;
1189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
1199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return a + b;
1209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
1219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* rotate list[0..len-1] left by rot positions, in place */
1239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal void rotate(unsigned char *list, unsigned len, unsigned rot)
1249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
1259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned char tmp;
1269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned cycles;
1279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned char *start, *last, *to, *from;
1289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* normalize rot and handle degenerate cases */
1309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (len < 2) return;
1319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (rot >= len) rot %= len;
1329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (rot == 0) return;
1339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* pointer to last entry in list */
1359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    last = list + (len - 1);
1369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* do simple left shift by one */
1389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (rot == 1) {
1399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        tmp = *list;
1409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        memcpy(list, list + 1, len - 1);
1419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        *last = tmp;
1429e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        return;
1439e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
1449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1459e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* do simple right shift by one */
1469e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (rot == len - 1) {
1479e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        tmp = *last;
1489e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        memmove(list + 1, list, len - 1);
1499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        *list = tmp;
1509e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        return;
1519e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
1529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* otherwise do rotate as a set of cycles in place */
1549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    cycles = gcd(len, rot);             /* number of cycles */
1559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    do {
1569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        start = from = list + cycles;   /* start index is arbitrary */
1579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        tmp = *from;                    /* save entry to be overwritten */
1589e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        for (;;) {
1599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            to = from;                  /* next step in cycle */
1609e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            from += rot;                /* go right rot positions */
1619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            if (from > last) from -= len;   /* (pointer better not wrap) */
1629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            if (from == start) break;   /* all but one shifted */
1639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            *to = *from;                /* shift left */
1649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
1659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        *to = tmp;                      /* complete the circle */
1669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    } while (--cycles);
1679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
1689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* structure for gzip file read operations */
1709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projecttypedef struct {
1719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int fd;                     /* file descriptor */
1729e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int size;                   /* 1 << size is bytes in buf */
1739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned left;              /* bytes available at next */
1749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned char *buf;         /* buffer */
17504351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes    z_const unsigned char *next;    /* next byte in buffer */
1769e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    char *name;                 /* file name for error messages */
1779e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project} file;
1789e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* reload buffer */
1809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal int readin(file *in)
1819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
1829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int len;
1839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    len = read(in->fd, in->buf, 1 << in->size);
1859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (len == -1) bye("error reading ", in->name);
1869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    in->left = (unsigned)len;
1879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    in->next = in->buf;
1889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return len;
1899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
1909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* read from file in, exit if end-of-file */
1929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal int readmore(file *in)
1939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
1949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (readin(in) == 0) bye("unexpected end of ", in->name);
1959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return 0;
1969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
1979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
1989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project#define read1(in) (in->left == 0 ? readmore(in) : 0, \
1999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                   in->left--, *(in->next)++)
2009e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* skip over n bytes of in */
2029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal void skip(file *in, unsigned n)
2039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
2049e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned bypass;
2059e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2069e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (n > in->left) {
2079e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        n -= in->left;
2089e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        bypass = n & ~((1U << in->size) - 1);
2099e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (bypass) {
2109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1)
2119e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                bye("seeking ", in->name);
2129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            n -= bypass;
2139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
2149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        readmore(in);
2159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (n > in->left)
2169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            bye("unexpected end of ", in->name);
2179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
2189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    in->left -= n;
2199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    in->next += n;
2209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
2219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* read a four-byte unsigned integer, little-endian, from in */
2239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectunsigned long read4(file *in)
2249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
2259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned long val;
2269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    val = read1(in);
2289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    val += (unsigned)read1(in) << 8;
2299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    val += (unsigned long)read1(in) << 16;
2309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    val += (unsigned long)read1(in) << 24;
2319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return val;
2329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
2339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* skip over gzip header */
2359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal void gzheader(file *in)
2369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
2379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int flags;
2389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned n;
2399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file");
2419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (read1(in) != 8) bye("unknown compression method in", in->name);
2429e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    flags = read1(in);
2439e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (flags & 0xe0) bye("unknown header flags set in", in->name);
2449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    skip(in, 6);
2459e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (flags & 4) {
2469e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        n = read1(in);
2479e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        n += (unsigned)(read1(in)) << 8;
2489e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        skip(in, n);
2499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
2509e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (flags & 8) while (read1(in) != 0) ;
2519e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (flags & 16) while (read1(in) != 0) ;
2529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (flags & 2) skip(in, 2);
2539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
2549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* decompress gzip file "name", return strm with a deflate stream ready to
2569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   continue compression of the data in the gzip file, and return a file
2579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   descriptor pointing to where to write the compressed data -- the deflate
2589e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   stream is initialized to compress using level "level" */
2599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal int gzscan(char *name, z_stream *strm, int level)
2609e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
2619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int ret, lastbit, left, full;
2629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned have;
2639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned long crc, tot;
2649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned char *window;
2659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    off_t lastoff, end;
2669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    file gz;
2679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* open gzip file */
2699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.name = name;
2709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.fd = open(name, O_RDWR, 0);
2719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (gz.fd == -1) bye("cannot open ", name);
2729e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.buf = malloc(CHUNK);
2739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (gz.buf == NULL) bye("out of memory", "");
2749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.size = LGCHUNK;
2759e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.left = 0;
2769e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2779e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* skip gzip header */
2789e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gzheader(&gz);
2799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* prepare to decompress */
2819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    window = malloc(DSIZE);
2829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (window == NULL) bye("out of memory", "");
2839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->zalloc = Z_NULL;
2849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->zfree = Z_NULL;
2859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->opaque = Z_NULL;
2869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    ret = inflateInit2(strm, -15);
2879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (ret != Z_OK) bye("out of memory", " or library mismatch");
2889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
2899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* decompress the deflate stream, saving append information */
2909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    lastbit = 0;
2919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
2929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    left = 0;
2939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->avail_in = gz.left;
2949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->next_in = gz.next;
2959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    crc = crc32(0L, Z_NULL, 0);
2969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    have = full = 0;
2979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    do {
2989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* if needed, get more input */
2999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (strm->avail_in == 0) {
3009e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            readmore(&gz);
3019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            strm->avail_in = gz.left;
3029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            strm->next_in = gz.next;
3039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
3049e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3059e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* set up output to next available section of sliding window */
3069e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        strm->avail_out = DSIZE - have;
3079e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        strm->next_out = window + have;
3089e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3099e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* inflate and check for errors */
3109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        ret = inflate(strm, Z_BLOCK);
3119e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (ret == Z_STREAM_ERROR) bye("internal stream error!", "");
3129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (ret == Z_MEM_ERROR) bye("out of memory", "");
3139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (ret == Z_DATA_ERROR)
3149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            bye("invalid compressed data--format violated in", name);
3159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* update crc and sliding window pointer */
3179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        crc = crc32(crc, window + have, DSIZE - have - strm->avail_out);
3189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (strm->avail_out)
3199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            have = DSIZE - strm->avail_out;
3209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        else {
3219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            have = 0;
3229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            full = 1;
3239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
3249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* process end of block */
3269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (strm->data_type & 128) {
3279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            if (strm->data_type & 64)
3289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                left = strm->data_type & 0x1f;
3299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            else {
3309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                lastbit = strm->data_type & 0x1f;
3319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in;
3329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            }
3339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
3349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    } while (ret != Z_STREAM_END);
3359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    inflateEnd(strm);
3369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.left = strm->avail_in;
3379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gz.next = strm->next_in;
3389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* save the location of the end of the compressed data */
3409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
3419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3429e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* check gzip trailer and save total for deflate */
3439e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (crc != read4(&gz))
3449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        bye("invalid compressed data--crc mismatch in ", name);
3459e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    tot = strm->total_out;
3469e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if ((tot & 0xffffffffUL) != read4(&gz))
3479e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        bye("invalid compressed data--length mismatch in", name);
3489e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* if not at end of file, warn */
3509e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (gz.left || readin(&gz))
3519e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        fprintf(stderr,
3529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            "gzappend warning: junk at end of gzip file overwritten\n");
3539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* clear last block bit */
3559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET);
3569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
3579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7)));
3589e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    lseek(gz.fd, -1L, SEEK_CUR);
3599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name);
3609e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* if window wrapped, build dictionary from window by rotating */
3629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (full) {
3639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        rotate(window, DSIZE, have);
3649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        have = DSIZE;
3659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
3669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* set up deflate stream with window, crc, total_in, and leftover bits */
3689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
3699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (ret != Z_OK) bye("out of memory", "");
3709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    deflateSetDictionary(strm, window, have);
3719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->adler = crc;
3729e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    strm->total_in = tot;
3739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (left) {
3749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        lseek(gz.fd, --end, SEEK_SET);
3759e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
3769e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        deflatePrime(strm, 8 - left, *gz.buf);
3779e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
3789e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    lseek(gz.fd, end, SEEK_SET);
3799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* clean up and return */
3819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    free(window);
3829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    free(gz.buf);
3839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return gz.fd;
3849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
3859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* append file "name" to gzip file gd using deflate stream strm -- if last
3879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   is true, then finish off the deflate stream at the end */
3889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectlocal void gztack(char *name, int gd, z_stream *strm, int last)
3899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
3909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int fd, len, ret;
3919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned left;
3929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    unsigned char *in, *out;
3939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
3949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* open file to compress and append */
3959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    fd = 0;
3969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (name != NULL) {
3979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        fd = open(name, O_RDONLY, 0);
3989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (fd == -1)
3999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            fprintf(stderr, "gzappend warning: %s not found, skipping ...\n",
4009e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                    name);
4019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
4029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* allocate buffers */
40404351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes    in = malloc(CHUNK);
4059e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    out = malloc(CHUNK);
40604351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes    if (in == NULL || out == NULL) bye("out of memory", "");
4079e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4089e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* compress input file and append to gzip file */
4099e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    do {
4109e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* get more input */
41104351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes        len = read(fd, in, CHUNK);
4129e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (len == -1) {
4139e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            fprintf(stderr,
4149e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                    "gzappend warning: error reading %s, skipping rest ...\n",
4159e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                    name);
4169e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            len = 0;
4179e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        }
4189e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        strm->avail_in = (unsigned)len;
4199e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        strm->next_in = in;
4209e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (len) strm->adler = crc32(strm->adler, in, (unsigned)len);
4219e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4229e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        /* compress and write all available output */
4239e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        do {
4249e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            strm->avail_out = CHUNK;
4259e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            strm->next_out = out;
4269e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH);
4279e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            left = CHUNK - strm->avail_out;
4289e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            while (left) {
4299e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                len = write(gd, out + CHUNK - strm->avail_out - left, left);
4309e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                if (len == -1) bye("writing gzip file", "");
4319e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project                left -= (unsigned)len;
4329e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            }
4339e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        } while (strm->avail_out == 0 && ret != Z_STREAM_END);
4349e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    } while (len != 0);
4359e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4369e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* write trailer after last entry */
4379e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (last) {
4389e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        deflateEnd(strm);
4399e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[0] = (unsigned char)(strm->adler);
4409e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[1] = (unsigned char)(strm->adler >> 8);
4419e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[2] = (unsigned char)(strm->adler >> 16);
4429e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[3] = (unsigned char)(strm->adler >> 24);
4439e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[4] = (unsigned char)(strm->total_in);
4449e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[5] = (unsigned char)(strm->total_in >> 8);
4459e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[6] = (unsigned char)(strm->total_in >> 16);
4469e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        out[7] = (unsigned char)(strm->total_in >> 24);
4479e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        len = 8;
4489e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        do {
4499e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            ret = write(gd, out + 8 - len, len);
4509e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            if (ret == -1) bye("writing gzip file", "");
4519e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            len -= ret;
4529e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        } while (len);
4539e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        close(gd);
4549e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
4559e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4569e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* clean up and return */
4579e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    free(out);
45804351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes    free(in);
4599e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (fd > 0) close(fd);
4609e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
4619e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4629e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project/* process the compression level option if present, scan the gzip file, and
4639e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   append the specified files, or append the data from stdin if no other file
4649e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   names are provided on the command line -- the gzip file must be writable
4659e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project   and seekable */
4669e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Projectint main(int argc, char **argv)
4679e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project{
4689e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    int gd, level;
4699e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    z_stream strm;
4709e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4719e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* ignore command name */
47204351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes    argc--; argv++;
4739e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4749e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* provide usage if no arguments */
4759e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (*argv == NULL) {
47604351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes        printf(
47704351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes            "gzappend 1.2 (11 Oct 2012) Copyright (C) 2003, 2012 Mark Adler\n"
47804351a92ecc8429c999acbfc5dfe5aa8bee1d19dElliott Hughes               );
4799e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        printf(
4809e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n");
4819e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        return 0;
4829e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
4839e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4849e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* set compression level */
4859e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    level = Z_DEFAULT_COMPRESSION;
4869e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (argv[0][0] == '-') {
4879e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0)
4889e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            bye("invalid compression level", "");
4899e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        level = argv[0][1] - '0';
4909e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        if (*++argv == NULL) bye("no gzip file name after options", "");
4919e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    }
4929e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4939e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* prepare to append to gzip file */
4949e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    gd = gzscan(*argv++, &strm, level);
4959e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project
4969e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    /* append files on command line, or from stdin if none */
4979e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    if (*argv == NULL)
4989e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        gztack(NULL, gd, &strm, 1);
4999e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    else
5009e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        do {
5019e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project            gztack(*argv, gd, &strm, argv[1] == NULL);
5029e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project        } while (*++argv != NULL);
5039e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project    return 0;
5049e38dfa2f95fce609707a0941f10af9a785288deThe Android Open Source Project}
505