Main Page | Class List | Directories | File List | Class Members | File Members

unzip.c

Go to the documentation of this file.
00001 /* unzip.c -- decompress files in gzip or pkzip format.
00002 
00003    Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
00004    Copyright (C) 1992-1993 Jean-loup Gailly
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software Foundation,
00018    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
00019 
00020 /*
00021  * The code in this file is derived from the file funzip.c written
00022  * and put in the public domain by Mark Adler.
00023  */
00024 
00025 /*
00026    This version can extract files in gzip or pkzip format.
00027    For the latter, only the first entry is extracted, and it has to be
00028    either deflated or stored.
00029  */
00030 
00031 #ifdef RCSID
00032 static char rcsid[] = "$Id: unzip.c,v 1.4 2006/11/20 08:40:34 eggert Exp $";
00033 #endif
00034 
00035 #include <config.h>
00036 #include "tailor.h"
00037 #include "gzip.h"
00038 #include "crypt.h"
00039 
00040 /* PKZIP header definitions */
00041 #define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
00042 #define LOCFLG 6                /* offset of bit flag */
00043 #define  CRPFLG 1               /*  bit for encrypted entry */
00044 #define  EXTFLG 8               /*  bit for extended local header */
00045 #define LOCHOW 8                /* offset of compression method */
00046 #define LOCTIM 10               /* file mod time (for decryption) */
00047 #define LOCCRC 14               /* offset of crc */
00048 #define LOCSIZ 18               /* offset of compressed size */
00049 #define LOCLEN 22               /* offset of uncompressed length */
00050 #define LOCFIL 26               /* offset of file name field length */
00051 #define LOCEXT 28               /* offset of extra field length */
00052 #define LOCHDR 30               /* size of local header, including sig */
00053 #define EXTHDR 16               /* size of extended local header, inc sig */
00054 #define RAND_HEAD_LEN  12       /* length of encryption random header */
00055 
00056 
00057 /* Globals */
00058 
00059 int decrypt;        /* flag to turn on decryption */
00060 char *key;          /* not used--needed to link crypt.c */
00061 int pkzip = 0;      /* set for a pkzip file */
00062 int ext_header = 0; /* set if extended local header */
00063 
00064 /* ===========================================================================
00065  * Check zip file and advance inptr to the start of the compressed data.
00066  * Get ofname from the local header if necessary.
00067  */
00068 int check_zipfile(in)
00069     int in;   /* input file descriptors */
00070 {
00071     uch *h = inbuf + inptr; /* first local header */
00072 
00073     ifd = in;
00074 
00075     /* Check validity of local header, and skip name and extra fields */
00076     inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
00077 
00078     if (inptr > insize || LG(h) != LOCSIG) {
00079         fprintf(stderr, "\n%s: %s: not a valid zip file\n",
00080                 program_name, ifname);
00081         exit_code = ERROR;
00082         return ERROR;
00083     }
00084     method = h[LOCHOW];
00085     if (method != STORED && method != DEFLATED) {
00086         fprintf(stderr,
00087                 "\n%s: %s: first entry not deflated or stored -- use unzip\n",
00088                 program_name, ifname);
00089         exit_code = ERROR;
00090         return ERROR;
00091     }
00092 
00093     /* If entry encrypted, decrypt and validate encryption header */
00094     if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
00095         fprintf(stderr, "\n%s: %s: encrypted file -- use unzip\n",
00096                 program_name, ifname);
00097         exit_code = ERROR;
00098         return ERROR;
00099     }
00100 
00101     /* Save flags for unzip() */
00102     ext_header = (h[LOCFLG] & EXTFLG) != 0;
00103     pkzip = 1;
00104 
00105     /* Get ofname and time stamp from local header (to be done) */
00106     return OK;
00107 }
00108 
00109 /* ===========================================================================
00110  * Unzip in to out.  This routine works on both gzip and pkzip files.
00111  *
00112  * IN assertions: the buffer inbuf contains already the beginning of
00113  *   the compressed data, from offsets inptr to insize-1 included.
00114  *   The magic header has already been checked. The output buffer is cleared.
00115  */
00116 int unzip(in, out)
00117     int in, out;   /* input and output file descriptors */
00118 {
00119     ulg orig_crc = 0;       /* original crc */
00120     ulg orig_len = 0;       /* original uncompressed length */
00121     int n;
00122     uch buf[EXTHDR];        /* extended local header */
00123     int err = OK;
00124 
00125     ifd = in;
00126     ofd = out;
00127 
00128     updcrc(NULL, 0);           /* initialize crc */
00129 
00130     if (pkzip && !ext_header) {  /* crc and length at the end otherwise */
00131         orig_crc = LG(inbuf + LOCCRC);
00132         orig_len = LG(inbuf + LOCLEN);
00133     }
00134 
00135     /* Decompress */
00136     if (method == DEFLATED)  {
00137 
00138         int res = inflate();
00139 
00140         if (res == 3) {
00141             xalloc_die ();
00142         } else if (res != 0) {
00143             gzip_error ("invalid compressed data--format violated");
00144         }
00145 
00146     } else if (pkzip && method == STORED) {
00147 
00148         register ulg n = LG(inbuf + LOCLEN);
00149 
00150         if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
00151 
00152             fprintf(stderr, "len %ld, siz %ld\n", n, LG(inbuf + LOCSIZ));
00153             gzip_error ("invalid compressed data--length mismatch");
00154         }
00155         while (n--) {
00156             uch c = (uch)get_byte();
00157             put_ubyte(c);
00158         }
00159         flush_window();
00160     } else {
00161         gzip_error ("internal error, invalid method");
00162     }
00163 
00164     /* Get the crc and original length */
00165     if (!pkzip) {
00166         /* crc32  (see algorithm.doc)
00167          * uncompressed input size modulo 2^32
00168          */
00169         for (n = 0; n < 8; n++) {
00170             buf[n] = (uch)get_byte(); /* may cause an error if EOF */
00171         }
00172         orig_crc = LG(buf);
00173         orig_len = LG(buf+4);
00174 
00175     } else if (ext_header) {  /* If extended header, check it */
00176         /* signature - 4bytes: 0x50 0x4b 0x07 0x08
00177          * CRC-32 value
00178          * compressed size 4-bytes
00179          * uncompressed size 4-bytes
00180          */
00181         for (n = 0; n < EXTHDR; n++) {
00182             buf[n] = (uch)get_byte(); /* may cause an error if EOF */
00183         }
00184         orig_crc = LG(buf+4);
00185         orig_len = LG(buf+12);
00186     }
00187 
00188     /* Validate decompression */
00189     if (orig_crc != updcrc(outbuf, 0)) {
00190         fprintf(stderr, "\n%s: %s: invalid compressed data--crc error\n",
00191                 program_name, ifname);
00192         err = ERROR;
00193     }
00194     if (orig_len != (ulg)(bytes_out & 0xffffffff)) {
00195         fprintf(stderr, "\n%s: %s: invalid compressed data--length error\n",
00196                 program_name, ifname);
00197         err = ERROR;
00198     }
00199 
00200     /* Check if there are more entries in a pkzip file */
00201     if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
00202         if (to_stdout) {
00203             WARN((stderr,
00204                   "%s: %s has more than one entry--rest ignored\n",
00205                   program_name, ifname));
00206         } else {
00207             /* Don't destroy the input zip file */
00208             fprintf(stderr,
00209                     "%s: %s has more than one entry -- unchanged\n",
00210                     program_name, ifname);
00211             err = ERROR;
00212         }
00213     }
00214     ext_header = pkzip = 0; /* for next file */
00215     if (err == OK) return OK;
00216     exit_code = ERROR;
00217     if (!test) abort_gzip();
00218     return err;
00219 }

© sourcejam.com 2005-2008