Logo Search packages:      
Sourcecode: ksh version File versions

ratz.c

/*
 * ratz -- read a tar gzip archive from the standard input
 *
 * coded for portability
 * _SEAR_* macros for win32 self extracting archives -- see sear(1).
 */

static char id[] = "\n@(#)$Id: ratz (Jean-loup Gailly, Mark Adler, Glenn Fowler) 2004-12-25 $\0\n";

#if _PACKAGE_ast

#include <ast.h>
#include <error.h>

static const char usage[] =
"[-?\n@(#)$Id: ratz (Jean-loup Gailly, Mark Adler, Glenn Fowler) 2004-12-25 $\n]"
"[-author?Jean-loup Gailly]"
"[-author?Mark Adler]"
"[-author?Glenn Fowler <gsf@research.att.com>]"
"[-copyright?Copyright (c) 1995-1998 Jean-loup Gailly and Mark Adler]"
"[-license?http://www.opensource.org/licenses/zlib-license]"
"[+NAME?ratz - read a tar gzip archive]"
"[+DESCRIPTION?\bratz\b extracts files and directories from a tar gzip"
"     archive on the standard input. It is a standalone program for systems"
"     that do not have \bpax\b(1), \btar\b(1) or \bgunzip\b(1). Only regular"
"     files and directories are extracted; all other file types are ignored.]"
"[+?\b.exe\b files generated by \bsear\b(1) are fully functional \bratz\b"
"     executables, so any \bratz\b option may be used on a \bsear\b file."
"     This allows \bsear\b file contents to be examined and extracted without"
"     executing any embedded installation scripts.]"
"[c:cat|uncompress?Uncompress the standard input and copy it to the standard"
"     output.]"
"[l:local?Reject files that traverse outside the current directory.]"
"[m:meter?Display a one line text meter showing archive read progress.]"
"[n!:convert?In ebcdic environments convert text archive members from ascii"
"     to the native ebcdic.]"
"[t:list?List each file path on the standard output but do not extract.]"
"[v:verbose?List each file path on the standard output as it is extracted.]"
"[V?Print the program version and exit.]"
"[+SEE ALSO?\bgunzip\b(1), \bpackage\b(1), \bpax\b(1), \bsear\b(1), \btar\b(1)]"
;

#else

#define NiL       ((char*)0)

#endif

#define METER_width     80
#define METER_parts     20

/* === gunzip.h === */
/*
 * stripped down zlib containing public gzfopen()+gzread() in one file
 * USE THE REAL ZLIB AFTER BOOTSTRAP
 */

#ifndef _GUNZIP_H
#define _GUNZIP_H 1

#include <stdio.h>
#include <sys/types.h>

#if _PACKAGE_ast || defined(__STDC__) || defined(_SEAR_EXEC) || defined(_WIN32)

#define FOPEN_READ      "rb"
#define FOPEN_WRITE     "wb"

#else

#define FOPEN_READ      "r"
#define FOPEN_WRITE     "w"

#endif

#if _PACKAGE_ast

#define setmode(d,m)

#else

#if !defined(_WINIX) && (_UWIN || __CYGWIN__ || __EMX__)
#define _WINIX          1
#endif

#if _WIN32 && !_WINIX

#include <direct.h>
#include <io.h>
#include <fcntl.h>
#include <windows.h>

#define mkdir(a,b)      mkdir(a)

#else

#include <unistd.h>

#define setmode(d,m)

#endif

#if defined(__STDC__)

#include <stdlib.h>
#include <string.h>

#endif

#endif

/* === zlib.h === */
/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.1.3, July 9th, 1998

  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu


  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
*/

/* === zconf.h === */
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
#  define WIN32
#endif
#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
#  ifndef __32BIT__
#    define __32BIT__
#  endif
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif

#if defined(MSDOS) && !defined(__32BIT__)
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
#  define STDC
#endif
#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
#  ifndef STDC
#    define STDC
#  endif
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const
#  endif
#endif

#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
#  define NEED_DUMMY_RETURN
#endif

#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
#  define SMALL_MEDIUM
#  ifdef _MSC_VER
#    define FAR _far
#  else
#    define FAR far
#  endif
#endif
#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
#  ifndef __32BIT__
#    define SMALL_MEDIUM
#    define FAR _far
#  endif
#endif

#if defined(ZLIB_DLL)
#  if defined(_WINDOWS) || defined(WINDOWS)
#    ifdef FAR
#      undef FAR
#    endif
#    include <windows.h>
#    define ZEXPORT  WINAPI
#    ifdef WIN32
#      define ZEXPORTVA  WINAPIV
#    else
#      define ZEXPORTVA  FAR _cdecl _export
#    endif
#  endif
#  if defined (__BORLANDC__)
#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
#      include <windows.h>
#      define ZEXPORT __declspec(dllexport) WINAPI
#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
#    else
#      if defined (_Windows) && defined (__DLL__)
#        define ZEXPORT _export
#        define ZEXPORTVA _export
#      endif
#    endif
#  endif
#endif

#if defined (__BEOS__)
#  if defined (ZLIB_DLL)
#    define ZEXTERN extern __declspec(dllexport)
#  else
#    define ZEXTERN extern __declspec(dllimport)
#  endif
#endif

#ifndef ZEXPORT
#  define ZEXPORT
#endif
#ifndef ZEXPORTVA
#  define ZEXPORTVA
#endif
#ifndef ZEXTERN
#  define ZEXTERN extern
#endif

#ifndef FAR
#   define FAR
#endif

#if !defined(MACOS) && !defined(TARGET_OS_MAC)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void FAR *voidpf;
   typedef void     *voidp;
#else
   typedef Byte FAR *voidpf;
   typedef Byte     *voidp;
#endif

#ifdef HAVE_UNISTD_H
#  include <sys/types.h> /* for off_t */
#  include <unistd.h>    /* for SEEK_* and off_t */
#  define z_off_t  off_t
#endif
#ifndef SEEK_SET
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
#  define  z_off_t long
#endif

#define ZLIB_VERSION "1.1.3"

typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void   (*free_func)  OF((voidpf opaque, voidpf address));

struct internal_state;

typedef struct z_stream_s {
    Bytef    *next_in;  /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total nb of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total nb of bytes output so far */

    char     *msg;      /* last error message, NULL if no error */
    struct internal_state FAR *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: ascii or binary */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
/* Allowed flush values; see deflate() below for details */

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative
 * values are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_ASCII    1
#define Z_UNKNOWN  2
/* Possible values of the data_type field */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

/* === zutil.h === */
#if !_PACKAGE_ast && !defined(STDC)
#if defined(__STDC__)
#  include <stddef.h>
#endif
#  include <string.h>
#  include <stdlib.h>
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL >= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#ifdef MSDOS
#  define OS_CODE  0x00
#  if defined(__TURBOC__) || defined(__BORLANDC__)
#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
       /* Allow compilation with ANSI keywords only enabled */
       void _Cdecl farfree( void *block );
       void *_Cdecl farmalloc( unsigned long nbytes );
#    else
#     include <alloc.h>
#    endif
#  else /* MSC or DJGPP */
#    include <malloc.h>
#  endif
#endif

#if defined(pyr)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
 /* Use our own functions for small and medium model with MSC <= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#endif

#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)

typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
                               uInt len));
#define ZALLOC(strm, items, size) \
           (*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

local voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
local void   zcfree  OF((voidpf opaque, voidpf ptr));

/* === zutil.c === */
#if 0 && !_PACKAGE_ast && !defined(STDC)
extern void exit OF((int));
#endif

#ifndef HAVE_MEMCPY

local void zmemcpy(dest, source, len)
    Bytef* dest;
    const Bytef* source;
    uInt  len;
{
    if (len == 0) return;
    do {
        *dest++ = *source++; /* ??? to be unrolled */
    } while (--len != 0);
}

local int zmemcmp(s1, s2, len)
    const Bytef* s1;
    const Bytef* s2;
    uInt  len;
{
    uInt j;

    for (j = 0; j < len; j++) {
        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
    }
    return 0;
}

local void zmemzero(dest, len)
    Bytef* dest;
    uInt  len;
{
    if (len == 0) return;
    do {
        *dest++ = 0;  /* ??? to be unrolled */
    } while (--len != 0);
}
#endif

#ifdef __TURBOC__
#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
/* Small and medium model in Turbo C are for now limited to near allocation
 * with reduced MAX_WBITS and MAX_MEM_LEVEL
 */
#  define MY_ZCALLOC

/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
 * and farmalloc(64K) returns a pointer with an offset of 8, so we
 * must fix the pointer. Warning: the pointer must be put back to its
 * original form in order to free it, use zcfree().
 */

#define MAX_PTR 10
/* 10*64K = 640K */

local int next_ptr = 0;

typedef struct ptr_table_s {
    voidpf org_ptr;
    voidpf new_ptr;
} ptr_table;

local ptr_table table[MAX_PTR];
/* This table is used to remember the original form of pointers
 * to large buffers (64K). Such pointers are normalized with a zero offset.
 * Since MSDOS is not a preemptive multitasking OS, this table is not
 * protected from concurrent access. This hack doesn't work anyway on
 * a protected system like OS/2. Use Microsoft C instead.
 */

local voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
{
    voidpf buf = opaque; /* just to make some compilers happy */
    ulg bsize = (ulg)items*size;

    /* If we allocate less than 65520 bytes, we assume that farmalloc
     * will return a usable pointer which doesn't have to be normalized.
     */
    if (bsize < 65520L) {
        buf = farmalloc(bsize);
        if (*(ush*)&buf != 0) return buf;
    } else {
        buf = farmalloc(bsize + 16L);
    }
    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
    table[next_ptr].org_ptr = buf;

    /* Normalize the pointer to seg:0 */
    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
    *(ush*)&buf = 0;
    table[next_ptr++].new_ptr = buf;
    return buf;
}

local void  zcfree (voidpf opaque, voidpf ptr)
{
    int n;
    if (*(ush*)&ptr != 0) { /* object < 64K */
        farfree(ptr);
        return;
    }
    /* Find the original pointer */
    for (n = 0; n < next_ptr; n++) {
        if (ptr != table[n].new_ptr) continue;

        farfree(table[n].org_ptr);
        while (++n < next_ptr) {
            table[n-1] = table[n];
        }
        next_ptr--;
        return;
    }
    ptr = opaque; /* just to make some compilers happy */
    Assert(0, "zcfree: ptr not found");
}
#endif
#endif /* __TURBOC__ */


#if defined(M_I86) && !defined(__32BIT__)
/* Microsoft C in 16-bit mode */

#  define MY_ZCALLOC

#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
#  define _halloc  halloc
#  define _hfree   hfree
#endif

local voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
{
    if (opaque) opaque = 0; /* to make compiler happy */
    return _halloc((long)items, size);
}

local void  zcfree (voidpf opaque, voidpf ptr)
{
    if (opaque) opaque = 0; /* to make compiler happy */
    _hfree(ptr);
}

#endif /* MSC */


#ifndef MY_ZCALLOC /* Any system without a special alloc function */

#if 0 && !_PACKAGE_ast && !defined(STDC)
extern voidp  calloc OF((uInt items, uInt size));
extern void   free   OF((voidpf ptr));
#endif

local voidpf zcalloc (opaque, items, size)
    voidpf opaque;
    unsigned items;
    unsigned size;
{
    if (opaque) items += size - size; /* make compiler happy */
    return (voidpf)calloc(items, size);
}

local void  zcfree (opaque, ptr)
    voidpf opaque;
    voidpf ptr;
{
    free(ptr);
    if (opaque) return; /* make compiler happy */
}

#endif /* MY_ZCALLOC */

/* === infblock.h === */
struct inflate_blocks_state;
typedef struct inflate_blocks_state FAR inflate_blocks_statef;

/* === inftrees.h === */
typedef struct inflate_huft_s FAR inflate_huft;

struct inflate_huft_s {
  struct {
    struct {
      Byte Exop;        /* number of extra bits or operation */
      Byte Bits;        /* number of bits in this code or subcode */
      uInt pad;         /* pad structure to a power of 2 (4 bytes for */
    } what;
  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
  uInt base;            /* literal, length base, distance base,
                           or table offset */
};

#define MANY 1440

/* === infcodes.h === */
struct inflate_codes_state;
typedef struct inflate_codes_state FAR inflate_codes_statef;

/* === infutil.h === */
typedef enum {
      TYPE,     /* get type bits (3, including end bit) */
      LENS,     /* get lengths for stored */
      STORED,   /* processing stored block */
      TABLE,    /* get table lengths */
      BTREE,    /* get bit lengths tree for a dynamic block */
      DTREE,    /* get length, distance trees for a dynamic block */
      CODES,    /* processing fixed or dynamic block */
      DRY,      /* output remaining window bytes */
      START,    /* x: set up for LEN */
      LEN,      /* i: get length/literal/eob next */
      LENEXT,   /* i: getting length extra (have base) */
      DIST,     /* i: get distance next */
      DISTEXT,  /* i: getting distance extra */
      COPY,     /* o: copying bytes in window, waiting for space */
      LIT,      /* o: got literal, waiting for output space */
      WASH,     /* o: got eob, possibly still output waiting */
      END,      /* x: got eob and all data flushed */
      BADCODE,  /* x: got error */
      METHOD,   /* waiting for method byte */
      FLAG,     /* waiting for flag byte */
      DICT4,    /* four dictionary check bytes to go */
      DICT3,    /* three dictionary check bytes to go */
      DICT2,    /* two dictionary check bytes to go */
      DICT1,    /* one dictionary check byte to go */
      DICT0,    /* waiting for inflateSetDictionary */
      BLOCKS,   /* decompressing blocks */
      CHECK4,   /* four check bytes to go */
      CHECK3,   /* three check bytes to go */
      CHECK2,   /* two check bytes to go */
      CHECK1,   /* one check byte to go */
      DONE,     /* finished last block, done */
      BAD}      /* got a data error--stuck here */
inflate_mode;
#define inflate_block_mode    inflate_mode
#define inflate_codes_mode    inflate_mode

struct inflate_blocks_state {
  /* mode */
  inflate_block_mode  mode;     /* current inflate_block mode */
  /* mode dependent information */
  union {
    uInt left;          /* if STORED, bytes left to copy */
    struct {
      uInt table;               /* table lengths (14 bits) */
      uInt index;               /* index into blens (or border) */
      uIntf *blens;             /* bit lengths of codes */
      uInt bb;                  /* bit length tree depth */
      inflate_huft *tb;         /* bit length decoding tree */
    } trees;            /* if DTREE, decoding info for trees */
    struct {
      inflate_codes_statef 
         *codes;
    } decode;           /* if CODES, current state */
  } sub;                /* submode */
  uInt last;            /* true if this block is the last block */
  /* mode independent information */
  uInt bitk;            /* bits in bit buffer */
  uLong bitb;           /* bit buffer */
  inflate_huft *hufts;  /* single malloc for tree space */
  Bytef *window;        /* sliding window */
  Bytef *end;           /* one byte after sliding window */
  Bytef *read;          /* window read pointer */
  Bytef *write;         /* window write pointer */
  check_func checkfn;   /* check function */
  uLong check;          /* check on output */
};

#define UPDBITS {s->bitb=b;s->bitk=k;}
#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
#define UPDOUT {s->write=q;}
#define UPDATE {UPDBITS UPDIN UPDOUT}
#define LEAVE {UPDATE return inflate_flush(s,z,r);}
/*   get bytes and bits */
#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
#define NEXTBYTE (n--,*p++)
#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
#define DUMPBITS(j) {b>>=(j);k-=(j);}
/*   output bytes */
#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
/*   load local pointers */
#define LOAD {LOADIN LOADOUT}

/* === infutil.c === */
/* And'ing with mask[n] masks the lower n bits */
uInt inflate_mask[17] = {
    0x0000,
    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};

/* copy as much as possible from the sliding window to the output area */
local int inflate_flush(s, z, r)
inflate_blocks_statef *s;
z_streamp z;
int r;
{
  uInt n;
  Bytef *p;
  Bytef *q;

  /* local copies of source and destination pointers */
  p = z->next_out;
  q = s->read;

  /* compute number of bytes to copy as far as end of window */
  n = (uInt)((q <= s->write ? s->write : s->end) - q);
  if (n > z->avail_out) n = z->avail_out;
  if (n && r == Z_BUF_ERROR) r = Z_OK;

  /* update counters */
  z->avail_out -= n;
  z->total_out += n;

  /* update check information */
  if (s->checkfn != Z_NULL)
    z->adler = s->check = (*s->checkfn)(s->check, q, n);

  /* copy as far as end of window */
  zmemcpy(p, q, n);
  p += n;
  q += n;

  /* see if more to copy at beginning of window */
  if (q == s->end)
  {
    /* wrap pointers */
    q = s->window;
    if (s->write == s->end)
      s->write = s->window;

    /* compute bytes to copy */
    n = (uInt)(s->write - q);
    if (n > z->avail_out) n = z->avail_out;
    if (n && r == Z_BUF_ERROR) r = Z_OK;

    /* update counters */
    z->avail_out -= n;
    z->total_out += n;

    /* update check information */
    if (s->checkfn != Z_NULL)
      z->adler = s->check = (*s->checkfn)(s->check, q, n);

    /* copy */
    zmemcpy(p, q, n);
    p += n;
    q += n;
  }

  /* update pointers */
  z->next_out = p;
  s->read = q;

  /* done */
  return r;
}

/* === inffixed.h === */
local uInt fixed_bl = 9;
local uInt fixed_bd = 5;
local inflate_huft fixed_tl[] = {
    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
  };
local inflate_huft fixed_td[] = {
    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
  };

/* === inftrees.c === */
const char inflate_copyright[] =
   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
/*
  If you use the zlib library in a product, an acknowledgment is welcome
  in the documentation of your product. If for some reason you cannot
  include such an acknowledgment, I would appreciate that you keep this
  copyright string in the executable of your product.
 */

/* simplify the use of the inflate_huft type with some defines */
#define exop word.what.Exop
#define bits word.what.Bits

/* Tables for deflate from PKZIP's appnote.txt. */
local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
        /* see note #13 above about 258 */
local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
        8193, 12289, 16385, 24577};
local const uInt cpdext[30] = { /* Extra bits for distance codes */
        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
        12, 12, 13, 13};

/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
#define BMAX 15         /* maximum bit length of any code */

local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
uInt n;                 /* number of codes (assumed <= 288) */
uInt s;                 /* number of simple-valued codes (0..s-1) */
const uIntf *d;         /* list of base values for non-simple codes */
const uIntf *e;         /* list of extra bits for non-simple codes */
inflate_huft * FAR *t;  /* result: starting table */
uIntf *m;               /* maximum lookup bits, returns actual */
inflate_huft *hp;       /* space for trees */
uInt *hn;               /* hufts used in space */
uIntf *v;               /* working area: values in order of bit length */
/* Given a list of code lengths and a maximum table size, make a set of
   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
   if the given code set is incomplete (the tables are still built in this
   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
   lengths), or Z_MEM_ERROR if not enough memory. */
{

  uInt a;                       /* counter for codes of length k */
  uInt c[BMAX+1];               /* bit length count table */
  uInt f;                       /* i repeats in table every f entries */
  int g;                        /* maximum code length */
  int h;                        /* table level */
  register uInt i;              /* counter, current code */
  register uInt j;              /* counter */
  register int k;               /* number of bits in current code */
  int l;                        /* bits per table (returned in m) */
  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
  register uIntf *p;            /* pointer into c[], b[], or v[] */
  inflate_huft *q;              /* points to current table */
  struct inflate_huft_s r;      /* table entry for structure assignment */
  inflate_huft *u[BMAX];        /* table stack */
  register int w;               /* bits before this table == (l * h) */
  uInt x[BMAX+1];               /* bit offsets, then code stack */
  uIntf *xp;                    /* pointer into x */
  int y;                        /* number of dummy codes added */
  uInt z;                       /* number of entries in current table */


  /* Generate counts for each bit length */
  p = c;
#define C0 *p++ = 0;
#define C2 C0 C0 C0 C0
#define C4 C2 C2 C2 C2
  C4                            /* clear c[]--assume BMAX+1 is 16 */
  p = b;  i = n;
  do {
    c[*p++]++;                  /* assume all entries <= BMAX */
  } while (--i);
  if (c[0] == n)                /* null input--all zero length codes */
  {
    *t = (inflate_huft *)Z_NULL;
    *m = 0;
    return Z_OK;
  }


  /* Find minimum and maximum length, bound *m by those */
  l = *m;
  for (j = 1; j <= BMAX; j++)
    if (c[j])
      break;
  k = j;                        /* minimum code length */
  if ((uInt)l < j)
    l = j;
  for (i = BMAX; i; i--)
    if (c[i])
      break;
  g = i;                        /* maximum code length */
  if ((uInt)l > i)
    l = i;
  *m = l;


  /* Adjust last length count to fill out codes, if needed */
  for (y = 1 << j; j < i; j++, y <<= 1)
    if ((y -= c[j]) < 0)
      return Z_DATA_ERROR;
  if ((y -= c[i]) < 0)
    return Z_DATA_ERROR;
  c[i] += y;


  /* Generate starting offsets into the value table for each length */
  x[1] = j = 0;
  p = c + 1;  xp = x + 2;
  while (--i) {                 /* note that i == g from above */
    *xp++ = (j += *p++);
  }


  /* Make a table of values in order of bit lengths */
  p = b;  i = 0;
  do {
    if ((j = *p++) != 0)
      v[x[j]++] = i;
  } while (++i < n);
  n = x[g];                     /* set n to length of v */


  /* Generate the Huffman codes and for each, make the table entries */
  x[0] = i = 0;                 /* first Huffman code is zero */
  p = v;                        /* grab values in bit order */
  h = -1;                       /* no tables yet--level -1 */
  w = -l;                       /* bits decoded == (l * h) */
  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
  q = (inflate_huft *)Z_NULL;   /* ditto */
  z = 0;                        /* ditto */

  /* go through the bit lengths (k already is bits in shortest code) */
  for (; k <= g; k++)
  {
    a = c[k];
    while (a--)
    {
      /* here i is the Huffman code of length k bits for value *p */
      /* make tables up to required level */
      while (k > w + l)
      {
        h++;
        w += l;                 /* previous table always l bits */

        /* compute minimum size table less than or equal to l bits */
        z = g - w;
        z = z > (uInt)l ? l : z;        /* table size upper limit */
        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
        {                       /* too few codes for k-w bit table */
          f -= a + 1;           /* deduct codes from patterns left */
          xp = c + k;
          if (j < z)
            while (++j < z)     /* try smaller tables up to z bits */
            {
              if ((f <<= 1) <= *++xp)
                break;          /* enough codes to use up j bits */
              f -= *xp;         /* else deduct codes from patterns */
            }
        }
        z = 1 << j;             /* table entries for j-bit table */

        /* allocate new table */
        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
          return Z_MEM_ERROR;   /* not enough memory */
        u[h] = q = hp + *hn;
        *hn += z;

        /* connect to last table, if there is one */
        if (h)
        {
          x[h] = i;             /* save pattern for backing up */
          r.bits = (Byte)l;     /* bits to dump before this table */
          r.exop = (Byte)j;     /* bits in this table */
          j = i >> (w - l);
          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
          u[h-1][j] = r;        /* connect to last table */
        }
        else
          *t = q;               /* first table is returned result */
      }

      /* set up table entry in r */
      r.bits = (Byte)(k - w);
      if (p >= v + n)
        r.exop = 128 + 64;      /* out of values--invalid code */
      else if (*p < s)
      {
        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
        r.base = *p++;          /* simple code is just the value */
      }
      else
      {
        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
        r.base = d[*p++ - s];
      }

      /* fill code-like entries with r */
      f = 1 << (k - w);
      for (j = i >> w; j < z; j += f)
        q[j] = r;

      /* backwards increment the k-bit code i */
      for (j = 1 << (k - 1); i & j; j >>= 1)
        i ^= j;
      i ^= j;

      /* backup over finished tables */
      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
      while ((i & mask) != x[h])
      {
        h--;                    /* don't need to update q */
        w -= l;
        mask = (1 << w) - 1;
      }
    }
  }


  /* Return Z_BUF_ERROR if we were given an incomplete table */
  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
}

local int inflate_trees_bits(c, bb, tb, hp, z)
uIntf *c;               /* 19 code lengths */
uIntf *bb;              /* bits tree desired/actual depth */
inflate_huft * FAR *tb; /* bits tree result */
inflate_huft *hp;       /* space for trees */
z_streamp z;            /* for messages */
{
  int r;
  uInt hn = 0;          /* hufts used in space */
  uIntf *v;             /* work area for huft_build */

  if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
    return Z_MEM_ERROR;
  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
                 tb, bb, hp, &hn, v);
  if (r == Z_DATA_ERROR)
    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
  else if (r == Z_BUF_ERROR || *bb == 0)
  {
    z->msg = (char*)"incomplete dynamic bit lengths tree";
    r = Z_DATA_ERROR;
  }
  ZFREE(z, v);
  return r;
}

local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
uInt nl;                /* number of literal/length codes */
uInt nd;                /* number of distance codes */
uIntf *c;               /* that many (total) code lengths */
uIntf *bl;              /* literal desired/actual bit depth */
uIntf *bd;              /* distance desired/actual bit depth */
inflate_huft * FAR *tl; /* literal/length tree result */
inflate_huft * FAR *td; /* distance tree result */
inflate_huft *hp;       /* space for trees */
z_streamp z;            /* for messages */
{
  int r;
  uInt hn = 0;          /* hufts used in space */
  uIntf *v;             /* work area for huft_build */

  /* allocate work area */
  if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
    return Z_MEM_ERROR;

  /* build literal/length tree */
  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
  if (r != Z_OK || *bl == 0)
  {
    if (r == Z_DATA_ERROR)
      z->msg = (char*)"oversubscribed literal/length tree";
    else if (r != Z_MEM_ERROR)
    {
      z->msg = (char*)"incomplete literal/length tree";
      r = Z_DATA_ERROR;
    }
    ZFREE(z, v);
    return r;
  }

  /* build distance tree */
  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
  if (r != Z_OK || (*bd == 0 && nl > 257))
  {
    if (r == Z_DATA_ERROR)
      z->msg = (char*)"oversubscribed distance tree";
    else if (r == Z_BUF_ERROR) {
#ifdef PKZIP_BUG_WORKAROUND
      r = Z_OK;
    }
#else
      z->msg = (char*)"incomplete distance tree";
      r = Z_DATA_ERROR;
    }
    else if (r != Z_MEM_ERROR)
    {
      z->msg = (char*)"empty distance tree with lengths";
      r = Z_DATA_ERROR;
    }
    ZFREE(z, v);
    return r;
#endif
  }

  /* done */
  ZFREE(z, v);
  return Z_OK;
}

local int inflate_trees_fixed(bl, bd, tl, td, z)
uIntf *bl;               /* literal desired/actual bit depth */
uIntf *bd;               /* distance desired/actual bit depth */
inflate_huft * FAR *tl;  /* literal/length tree result */
inflate_huft * FAR *td;  /* distance tree result */
z_streamp z;             /* for memory allocation */
{
#ifdef BUILDFIXED
  /* build fixed tables if not already */
  if (!fixed_built)
  {
    int k;              /* temporary variable */
    uInt f = 0;         /* number of hufts used in fixed_mem */
    uIntf *c;           /* length list for huft_build */
    uIntf *v;           /* work area for huft_build */

    /* allocate memory */
    if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
      return Z_MEM_ERROR;
    if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
    {
      ZFREE(z, c);
      return Z_MEM_ERROR;
    }

    /* literal table */
    for (k = 0; k < 144; k++)
      c[k] = 8;
    for (; k < 256; k++)
      c[k] = 9;
    for (; k < 280; k++)
      c[k] = 7;
    for (; k < 288; k++)
      c[k] = 8;
    fixed_bl = 9;
    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
               fixed_mem, &f, v);

    /* distance table */
    for (k = 0; k < 30; k++)
      c[k] = 5;
    fixed_bd = 5;
    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
               fixed_mem, &f, v);

    /* done */
    ZFREE(z, v);
    ZFREE(z, c);
    fixed_built = 1;
  }
#endif
  *bl = fixed_bl;
  *bd = fixed_bd;
  *tl = fixed_tl;
  *td = fixed_td;
  return Z_OK;
}

/* === inffast.c === */
/* macros for bit input with no checking and for returning unused bytes */
#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}

local int inflate_fast(bl, bd, tl, td, s, z)
uInt bl, bd;
inflate_huft *tl;
inflate_huft *td; /* need separate declaration for Borland C++ */
inflate_blocks_statef *s;
z_streamp z;
{
  inflate_huft *t;      /* temporary pointer */
  uInt e;               /* extra bits or operation */
  uLong b;              /* bit buffer */
  uInt k;               /* bits in bit buffer */
  Bytef *p;             /* input data pointer */
  uInt n;               /* bytes available there */
  Bytef *q;             /* output window write pointer */
  uInt m;               /* bytes to end of window or read pointer */
  uInt ml;              /* mask for literal/length tree */
  uInt md;              /* mask for distance tree */
  uInt c;               /* bytes to copy */
  uInt d;               /* distance back to copy from */
  Bytef *r;             /* copy source pointer */

  /* load input, output, bit values */
  LOAD

  /* initialize masks */
  ml = inflate_mask[bl];
  md = inflate_mask[bd];

  /* do until not enough input or output space for fast loop */
  do {                          /* assume called with m >= 258 && n >= 10 */
    /* get literal/length code */
    GRABBITS(20)                /* max bits for literal/length code */
    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
    {
      DUMPBITS(t->bits)
      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
                "inflate:         * literal '%c'\n" :
                "inflate:         * literal 0x%02x\n", t->base));
      *q++ = (Byte)t->base;
      m--;
      continue;
    }
    do {
      DUMPBITS(t->bits)
      if (e & 16)
      {
        /* get extra bits for length */
        e &= 15;
        c = t->base + ((uInt)b & inflate_mask[e]);
        DUMPBITS(e)
        Tracevv((stderr, "inflate:         * length %u\n", c));

        /* decode distance base of block to copy */
        GRABBITS(15);           /* max bits for distance code */
        e = (t = td + ((uInt)b & md))->exop;
        do {
          DUMPBITS(t->bits)
          if (e & 16)
          {
            /* get extra bits to add to distance base */
            e &= 15;
            GRABBITS(e)         /* get extra bits (up to 13) */
            d = t->base + ((uInt)b & inflate_mask[e]);
            DUMPBITS(e)
            Tracevv((stderr, "inflate:         * distance %u\n", d));

            /* do the copy */
            m -= c;
            if ((uInt)(q - s->window) >= d)     /* offset before dest */
            {                                   /*  just copy */
              r = q - d;
              *q++ = *r++;  c--;        /* minimum count is three, */
              *q++ = *r++;  c--;        /*  so unroll loop a little */
            }
            else                        /* else offset after destination */
            {
              e = d - (uInt)(q - s->window); /* bytes from offset to end */
              r = s->end - e;           /* pointer to offset */
              if (c > e)                /* if source crosses, */
              {
                c -= e;                 /* copy to end of window */
                do {
                  *q++ = *r++;
                } while (--e);
                r = s->window;          /* copy rest from start of window */
              }
            }
            do {                        /* copy all or what's left */
              *q++ = *r++;
            } while (--c);
            break;
          }
          else if ((e & 64) == 0)
          {
            t += t->base;
            e = (t += ((uInt)b & inflate_mask[e]))->exop;
          }
          else
          {
            z->msg = (char*)"invalid distance code";
            UNGRAB
            UPDATE
            return Z_DATA_ERROR;
          }
        } while (1);
        break;
      }
      if ((e & 64) == 0)
      {
        t += t->base;
        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
        {
          DUMPBITS(t->bits)
          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
                    "inflate:         * literal '%c'\n" :
                    "inflate:         * literal 0x%02x\n", t->base));
          *q++ = (Byte)t->base;
          m--;
          break;
        }
      }
      else if (e & 32)
      {
        Tracevv((stderr, "inflate:         * end of block\n"));
        UNGRAB
        UPDATE
        return Z_STREAM_END;
      }
      else
      {
        z->msg = (char*)"invalid literal/length code";
        UNGRAB
        UPDATE
        return Z_DATA_ERROR;
      }
    } while (1);
  } while (m >= 258 && n >= 10);

  /* not enough input or output--restore pointers and return */
  UNGRAB
  UPDATE
  return Z_OK;
}

/* === infcodes.c === */
/* inflate codes private state */
struct inflate_codes_state {

  /* mode */
  inflate_codes_mode mode;      /* current inflate_codes mode */

  /* mode dependent information */
  uInt len;
  union {
    struct {
      inflate_huft *tree;       /* pointer into tree */
      uInt need;                /* bits needed */
    } code;             /* if LEN or DIST, where in tree */
    uInt lit;           /* if LIT, literal */
    struct {
      uInt get;                 /* bits to get for extra */
      uInt dist;                /* distance back to copy from */
    } copy;             /* if EXT or COPY, where and how much */
  } sub;                /* submode */

  /* mode independent information */
  Byte lbits;           /* ltree bits decoded per branch */
  Byte dbits;           /* dtree bits decoder per branch */
  inflate_huft *ltree;          /* literal/length/eob tree */
  inflate_huft *dtree;          /* distance tree */

};

local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
uInt bl, bd;
inflate_huft *tl;
inflate_huft *td; /* need separate declaration for Borland C++ */
z_streamp z;
{
  inflate_codes_statef *c;

  if ((c = (inflate_codes_statef *)
       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
  {
    c->mode = START;
    c->lbits = (Byte)bl;
    c->dbits = (Byte)bd;
    c->ltree = tl;
    c->dtree = td;
    Tracev((stderr, "inflate:       codes new\n"));
  }
  return c;
}

local int inflate_codes(s, z, r)
inflate_blocks_statef *s;
z_streamp z;
int r;
{
  uInt j;               /* temporary storage */
  inflate_huft *t;      /* temporary pointer */
  uInt e;               /* extra bits or operation */
  uLong b;              /* bit buffer */
  uInt k;               /* bits in bit buffer */
  Bytef *p;             /* input data pointer */
  uInt n;               /* bytes available there */
  Bytef *q;             /* output window write pointer */
  uInt m;               /* bytes to end of window or read pointer */
  Bytef *f;             /* pointer to copy strings from */
  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */

  /* copy input/output information to locals (UPDATE macro restores) */
  LOAD

  /* process input and output based on current state */
  while (1) switch (c->mode)
  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
    case START:         /* x: set up for LEN */
#ifndef SLOW
      if (m >= 258 && n >= 10)
      {
        UPDATE
        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
        LOAD
        if (r != Z_OK)
        {
          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
          break;
        }
      }
#endif /* !SLOW */
      c->sub.code.need = c->lbits;
      c->sub.code.tree = c->ltree;
      c->mode = LEN;
    case LEN:           /* i: get length/literal/eob next */
      j = c->sub.code.need;
      NEEDBITS(j)
      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
      DUMPBITS(t->bits)
      e = (uInt)(t->exop);
      if (e == 0)               /* literal */
      {
        c->sub.lit = t->base;
        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
                 "inflate:         literal '%c'\n" :
                 "inflate:         literal 0x%02x\n", t->base));
        c->mode = LIT;
        break;
      }
      if (e & 16)               /* length */
      {
        c->sub.copy.get = e & 15;
        c->len = t->base;
        c->mode = LENEXT;
        break;
      }
      if ((e & 64) == 0)        /* next table */
      {
        c->sub.code.need = e;
        c->sub.code.tree = t + t->base;
        break;
      }
      if (e & 32)               /* end of block */
      {
        Tracevv((stderr, "inflate:         end of block\n"));
        c->mode = WASH;
        break;
      }
      c->mode = BADCODE;        /* invalid code */
      z->msg = (char*)"invalid literal/length code";
      r = Z_DATA_ERROR;
      LEAVE
    case LENEXT:        /* i: getting length extra (have base) */
      j = c->sub.copy.get;
      NEEDBITS(j)
      c->len += (uInt)b & inflate_mask[j];
      DUMPBITS(j)
      c->sub.code.need = c->dbits;
      c->sub.code.tree = c->dtree;
      Tracevv((stderr, "inflate:         length %u\n", c->len));
      c->mode = DIST;
    case DIST:          /* i: get distance next */
      j = c->sub.code.need;
      NEEDBITS(j)
      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
      DUMPBITS(t->bits)
      e = (uInt)(t->exop);
      if (e & 16)               /* distance */
      {
        c->sub.copy.get = e & 15;
        c->sub.copy.dist = t->base;
        c->mode = DISTEXT;
        break;
      }
      if ((e & 64) == 0)        /* next table */
      {
        c->sub.code.need = e;
        c->sub.code.tree = t + t->base;
        break;
      }
      c->mode = BADCODE;        /* invalid code */
      z->msg = (char*)"invalid distance code";
      r = Z_DATA_ERROR;
      LEAVE
    case DISTEXT:       /* i: getting distance extra */
      j = c->sub.copy.get;
      NEEDBITS(j)
      c->sub.copy.dist += (uInt)b & inflate_mask[j];
      DUMPBITS(j)
      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
      c->mode = COPY;
    case COPY:          /* o: copying bytes in window, waiting for space */
#ifndef __TURBOC__ /* Turbo C bug for following expression */
      f = (uInt)(q - s->window) < c->sub.copy.dist ?
          s->end - (c->sub.copy.dist - (q - s->window)) :
          q - c->sub.copy.dist;
#else
      f = q - c->sub.copy.dist;
      if ((uInt)(q - s->window) < c->sub.copy.dist)
        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
#endif
      while (c->len)
      {
        NEEDOUT
        OUTBYTE(*f++)
        if (f == s->end)
          f = s->window;
        c->len--;
      }
      c->mode = START;
      break;
    case LIT:           /* o: got literal, waiting for output space */
      NEEDOUT
      OUTBYTE(c->sub.lit)
      c->mode = START;
      break;
    case WASH:          /* o: got eob, possibly more output */
      if (k > 7)        /* return unused byte, if any */
      {
        Assert(k < 16, "inflate_codes grabbed too many bytes")
        k -= 8;
        n++;
        p--;            /* can always return one */
      }
      FLUSH
      if (s->read != s->write)
        LEAVE
      c->mode = END;
    case END:
      r = Z_STREAM_END;
      LEAVE
    case BADCODE:       /* x: got error */
      r = Z_DATA_ERROR;
      LEAVE
    default:
      r = Z_STREAM_ERROR;
      LEAVE
  }
#ifdef NEED_DUMMY_RETURN
  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
#endif
}


local void inflate_codes_free(c, z)
inflate_codes_statef *c;
z_streamp z;
{
  ZFREE(z, c);
  Tracev((stderr, "inflate:       codes free\n"));
}

/* === infblock.c === */
/* Table for deflate from PKZIP's appnote.txt. */
local const uInt border[] = { /* Order of the bit length code lengths */
        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};

local void inflate_blocks_reset(s, z, c)
inflate_blocks_statef *s;
z_streamp z;
uLongf *c;
{
  if (c != Z_NULL)
    *c = s->check;
  if (s->mode == BTREE || s->mode == DTREE)
    ZFREE(z, s->sub.trees.blens);
  if (s->mode == CODES)
    inflate_codes_free(s->sub.decode.codes, z);
  s->mode = TYPE;
  s->bitk = 0;
  s->bitb = 0;
  s->read = s->write = s->window;
  if (s->checkfn != Z_NULL)
    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
  Tracev((stderr, "inflate:   blocks reset\n"));
}

local inflate_blocks_statef *inflate_blocks_new(z, c, w)
z_streamp z;
check_func c;
uInt w;
{
  inflate_blocks_statef *s;

  if ((s = (inflate_blocks_statef *)ZALLOC
       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
    return s;
  if ((s->hufts =
       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
  {
    ZFREE(z, s);
    return Z_NULL;
  }
  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
  {
    ZFREE(z, s->hufts);
    ZFREE(z, s);
    return Z_NULL;
  }
  s->end = s->window + w;
  s->checkfn = c;
  s->mode = TYPE;
  Tracev((stderr, "inflate:   blocks allocated\n"));
  inflate_blocks_reset(s, z, Z_NULL);
  return s;
}

local int inflate_blocks(s, z, r)
inflate_blocks_statef *s;
z_streamp z;
int r;
{
  uInt t;               /* temporary storage */
  uLong b;              /* bit buffer */
  uInt k;               /* bits in bit buffer */
  Bytef *p;             /* input data pointer */
  uInt n;               /* bytes available there */
  Bytef *q;             /* output window write pointer */
  uInt m;               /* bytes to end of window or read pointer */

  /* copy input/output information to locals (UPDATE macro restores) */
  LOAD

  /* process input based on current state */
  while (1) switch (s->mode)
  {
    case TYPE:
      NEEDBITS(3)
      t = (uInt)b & 7;
      s->last = t & 1;
      switch (t >> 1)
      {
        case 0:                         /* stored */
          Tracev((stderr, "inflate:     stored block%s\n",
                 s->last ? " (last)" : ""));
          DUMPBITS(3)
          t = k & 7;                    /* go to byte boundary */
          DUMPBITS(t)
          s->mode = LENS;               /* get length of stored block */
          break;
        case 1:                         /* fixed */
          Tracev((stderr, "inflate:     fixed codes block%s\n",
                 s->last ? " (last)" : ""));
          {
            uInt bl, bd;
            inflate_huft *tl, *td;

            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
            if (s->sub.decode.codes == Z_NULL)
            {
              r = Z_MEM_ERROR;
              LEAVE
            }
          }
          DUMPBITS(3)
          s->mode = CODES;
          break;
        case 2:                         /* dynamic */
          Tracev((stderr, "inflate:     dynamic codes block%s\n",
                 s->last ? " (last)" : ""));
          DUMPBITS(3)
          s->mode = TABLE;
          break;
        case 3:                         /* illegal */
          DUMPBITS(3)
          s->mode = BAD;
          z->msg = (char*)"invalid block type";
          r = Z_DATA_ERROR;
          LEAVE
      }
      break;
    case LENS:
      NEEDBITS(32)
      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
      {
        s->mode = BAD;
        z->msg = (char*)"invalid stored block lengths";
        r = Z_DATA_ERROR;
        LEAVE
      }
      s->sub.left = (uInt)b & 0xffff;
      b = k = 0;                      /* dump bits */
      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
      break;
    case STORED:
      if (n == 0)
        LEAVE
      NEEDOUT
      t = s->sub.left;
      if (t > n) t = n;
      if (t > m) t = m;
      zmemcpy(q, p, t);
      p += t;  n -= t;
      q += t;  m -= t;
      if ((s->sub.left -= t) != 0)
        break;
      Tracev((stderr, "inflate:       stored end, %lu total out\n",
              z->total_out + (q >= s->read ? q - s->read :
              (s->end - s->read) + (q - s->window))));
      s->mode = s->last ? DRY : TYPE;
      break;
    case TABLE:
      NEEDBITS(14)
      s->sub.trees.table = t = (uInt)b & 0x3fff;
#ifndef PKZIP_BUG_WORKAROUND
      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
      {
        s->mode = BAD;
        z->msg = (char*)"too many length or distance symbols";
        r = Z_DATA_ERROR;
        LEAVE
      }
#endif
      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
      {
        r = Z_MEM_ERROR;
        LEAVE
      }
      DUMPBITS(14)
      s->sub.trees.index = 0;
      Tracev((stderr, "inflate:       table sizes ok\n"));
      s->mode = BTREE;
    case BTREE:
      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
      {
        NEEDBITS(3)
        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
        DUMPBITS(3)
      }
      while (s->sub.trees.index < 19)
        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
      s->sub.trees.bb = 7;
      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
                             &s->sub.trees.tb, s->hufts, z);
      if (t != Z_OK)
      {
        ZFREE(z, s->sub.trees.blens);
        r = t;
        if (r == Z_DATA_ERROR)
          s->mode = BAD;
        LEAVE
      }
      s->sub.trees.index = 0;
      Tracev((stderr, "inflate:       bits tree ok\n"));
      s->mode = DTREE;
    case DTREE:
      while (t = s->sub.trees.table,
             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
      {
        inflate_huft *h;
        uInt i, j, c;

        t = s->sub.trees.bb;
        NEEDBITS(t)
        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
        t = h->bits;
        c = h->base;
        if (c < 16)
        {
          DUMPBITS(t)
          s->sub.trees.blens[s->sub.trees.index++] = c;
        }
        else /* c == 16..18 */
        {
          i = c == 18 ? 7 : c - 14;
          j = c == 18 ? 11 : 3;
          NEEDBITS(t + i)
          DUMPBITS(t)
          j += (uInt)b & inflate_mask[i];
          DUMPBITS(i)
          i = s->sub.trees.index;
          t = s->sub.trees.table;
          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
              (c == 16 && i < 1))
          {
            ZFREE(z, s->sub.trees.blens);
            s->mode = BAD;
            z->msg = (char*)"invalid bit length repeat";
            r = Z_DATA_ERROR;
            LEAVE
          }
          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
          do {
            s->sub.trees.blens[i++] = c;
          } while (--j);
          s->sub.trees.index = i;
        }
      }
      s->sub.trees.tb = Z_NULL;
      {
        uInt bl, bd;
        inflate_huft *tl, *td;
        inflate_codes_statef *c;

        bl = 9;         /* must be <= 9 for lookahead assumptions */
        bd = 6;         /* must be <= 9 for lookahead assumptions */
        t = s->sub.trees.table;
        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
                                  s->hufts, z);
        ZFREE(z, s->sub.trees.blens);
        if (t != Z_OK)
        {
          if (t == (uInt)Z_DATA_ERROR)
            s->mode = BAD;
          r = t;
          LEAVE
        }
        Tracev((stderr, "inflate:       trees ok\n"));
        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
        {
          r = Z_MEM_ERROR;
          LEAVE
        }
        s->sub.decode.codes = c;
      }
      s->mode = CODES;
    case CODES:
      UPDATE
      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
        return inflate_flush(s, z, r);
      r = Z_OK;
      inflate_codes_free(s->sub.decode.codes, z);
      LOAD
      Tracev((stderr, "inflate:       codes end, %lu total out\n",
              z->total_out + (q >= s->read ? q - s->read :
              (s->end - s->read) + (q - s->window))));
      if (!s->last)
      {
        s->mode = TYPE;
        break;
      }
      s->mode = DRY;
    case DRY:
      FLUSH
      if (s->read != s->write)
        LEAVE
      s->mode = DONE;
    case DONE:
      r = Z_STREAM_END;
      LEAVE
    case BAD:
      r = Z_DATA_ERROR;
      LEAVE
    default:
      r = Z_STREAM_ERROR;
      LEAVE
  }
}

local int inflate_blocks_free(s, z)
inflate_blocks_statef *s;
z_streamp z;
{
  inflate_blocks_reset(s, z, Z_NULL);
  ZFREE(z, s->window);
  ZFREE(z, s->hufts);
  ZFREE(z, s);
  Tracev((stderr, "inflate:   blocks freed\n"));
  return Z_OK;
}


local void inflate_set_dictionary(s, d, n)
inflate_blocks_statef *s;
const Bytef *d;
uInt  n;
{
  zmemcpy(s->window, d, n);
  s->read = s->write = s->window + n;
}

/* Returns true if inflate is currently at the end of a block generated
 * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
 * IN assertion: s != Z_NULL
 */
local int inflate_blocks_sync_point(s)
inflate_blocks_statef *s;
{
  return s->mode == LENS;
}

/* === inflate.c === */
/* inflate private state */
struct internal_state {

  /* mode */
  inflate_mode  mode;   /* current inflate mode */

  /* mode dependent information */
  union {
    uInt method;        /* if FLAGS, method byte */
    struct {
      uLong was;                /* computed check value */
      uLong need;               /* stream check value */
    } check;            /* if CHECK, check values to compare */
    uInt marker;        /* if BAD, inflateSync's marker bytes count */
  } sub;        /* submode */

  /* mode independent information */
  int  nowrap;          /* flag for no wrapper */
  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
  inflate_blocks_statef 
    *blocks;            /* current inflate_blocks state */

};

local int ZEXPORT inflateReset(z)
z_streamp z;
{
  if (z == Z_NULL || z->state == Z_NULL)
    return Z_STREAM_ERROR;
  z->total_in = z->total_out = 0;
  z->msg = Z_NULL;
  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
  Tracev((stderr, "inflate: reset\n"));
  return Z_OK;
}

local int ZEXPORT inflateEnd(z)
z_streamp z;
{
  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
    return Z_STREAM_ERROR;
  if (z->state->blocks != Z_NULL)
    inflate_blocks_free(z->state->blocks, z);
  ZFREE(z, z->state);
  z->state = Z_NULL;
  Tracev((stderr, "inflate: end\n"));
  return Z_OK;
}

local int ZEXPORT inflateInit2(z, w, version, stream_size)
z_streamp z;
int w;
const char *version;
int stream_size;
{
  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
      stream_size != sizeof(z_stream))
      return Z_VERSION_ERROR;

  /* initialize state */
  if (z == Z_NULL)
    return Z_STREAM_ERROR;
  z->msg = Z_NULL;
  if (z->zalloc == Z_NULL)
  {
    z->zalloc = zcalloc;
    z->opaque = (voidpf)0;
  }
  if (z->zfree == Z_NULL) z->zfree = zcfree;
  if ((z->state = (struct internal_state FAR *)
       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
    return Z_MEM_ERROR;
  z->state->blocks = Z_NULL;

  /* handle undocumented nowrap option (no zlib header or check) */
  z->state->nowrap = 0;
  if (w < 0)
  {
    w = - w;
    z->state->nowrap = 1;
  }

  /* set window size */
  if (w < 8 || w > 15)
  {
    inflateEnd(z);
    return Z_STREAM_ERROR;
  }
  z->state->wbits = (uInt)w;

  /* create inflate_blocks state */
  if ((z->state->blocks =
#ifdef _GUNZIP_H
      inflate_blocks_new(z, Z_NULL, (uInt)1 << w))
#else
      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
#endif
      == Z_NULL)
  {
    inflateEnd(z);
    return Z_MEM_ERROR;
  }
  Tracev((stderr, "inflate: allocated\n"));

  /* reset state */
  inflateReset(z);
  return Z_OK;
}

#undef      NEEDBYTE
#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
#undef      NEXTBYTE
#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)

local int ZEXPORT inflate(z, f)
z_streamp z;
int f;
{
  int r;
  uInt b;

  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
    return Z_STREAM_ERROR;
  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
  r = Z_BUF_ERROR;
  while (1) switch (z->state->mode)
  {
    case METHOD:
      NEEDBYTE
      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
      {
        z->state->mode = BAD;
        z->msg = (char*)"unknown compression method";
        z->state->sub.marker = 5;       /* can't try inflateSync */
        break;
      }
      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
      {
        z->state->mode = BAD;
        z->msg = (char*)"invalid window size";
        z->state->sub.marker = 5;       /* can't try inflateSync */
        break;
      }
      z->state->mode = FLAG;
    case FLAG:
      NEEDBYTE
      b = NEXTBYTE;
      if (((z->state->sub.method << 8) + b) % 31)
      {
        z->state->mode = BAD;
        z->msg = (char*)"incorrect header check";
        z->state->sub.marker = 5;       /* can't try inflateSync */
        break;
      }
      Tracev((stderr, "inflate: zlib header ok\n"));
      if (!(b & PRESET_DICT))
      {
        z->state->mode = BLOCKS;
        break;
      }
      z->state->mode = DICT4;
    case DICT4:
      NEEDBYTE
      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
      z->state->mode = DICT3;
    case DICT3:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
      z->state->mode = DICT2;
    case DICT2:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
      z->state->mode = DICT1;
    case DICT1:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE;
      z->adler = z->state->sub.check.need;
      z->state->mode = DICT0;
      return Z_NEED_DICT;
    case DICT0:
      z->state->mode = BAD;
      z->msg = (char*)"need dictionary";
      z->state->sub.marker = 0;       /* can try inflateSync */
      return Z_STREAM_ERROR;
    case BLOCKS:
      r = inflate_blocks(z->state->blocks, z, r);
      if (r == Z_DATA_ERROR)
      {
        z->state->mode = BAD;
        z->state->sub.marker = 0;       /* can try inflateSync */
        break;
      }
      if (r == Z_OK)
        r = f;
      if (r != Z_STREAM_END)
        return r;
      r = f;
      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
      if (z->state->nowrap)
      {
        z->state->mode = DONE;
        break;
      }
      z->state->mode = CHECK4;
    case CHECK4:
      NEEDBYTE
      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
      z->state->mode = CHECK3;
    case CHECK3:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
      z->state->mode = CHECK2;
    case CHECK2:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
      z->state->mode = CHECK1;
    case CHECK1:
      NEEDBYTE
      z->state->sub.check.need += (uLong)NEXTBYTE;

      if (z->state->sub.check.was != z->state->sub.check.need)
      {
        z->state->mode = BAD;
        z->msg = (char*)"incorrect data check";
        z->state->sub.marker = 5;       /* can't try inflateSync */
        break;
      }
      Tracev((stderr, "inflate: zlib check ok\n"));
      z->state->mode = DONE;
    case DONE:
      return Z_STREAM_END;
    case BAD:
      return Z_DATA_ERROR;
    default:
      return Z_STREAM_ERROR;
  }
#ifdef NEED_DUMMY_RETURN
  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
#endif
}

/* === gzio.c === */
typedef void* gzFile;

#ifndef Z_BUFSIZE
#  ifdef MAXSEG_64K
#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
#  else
#    define Z_BUFSIZE 16384
#  endif
#endif
#ifndef Z_PRINTF_BUFSIZE
#  define Z_PRINTF_BUFSIZE 4096
#endif

#define ALLOC(size) malloc(size)
#define TRYFREE(p) {if (p) free(p);}

static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */

/* gzip flag byte */
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
#define COMMENT      0x10 /* bit 4 set: file comment present */
#define RESERVED     0xE0 /* bits 5..7: reserved */

typedef struct gz_stream {
    z_stream stream;
    int      z_err;   /* error code for last stream operation */
    int      z_eof;   /* set if end of input file */
    FILE     *file;   /* .gz file */
    Byte     *inbuf;  /* input buffer */
    Byte     *outbuf; /* output buffer */
    uLong    crc;     /* crc32 of uncompressed data */
    char     *msg;    /* error message */
    char     *path;   /* path name for debugging only */
    int      transparent; /* 1 if input file is not a .gz file */
    int          verified;/* 2-byte magic read and verified ('v') */
    char     mode;    /* 'w' or 'r' */
    long     startpos; /* start of compressed data in file (header skipped) */
} gz_stream;

local int getByte(s)
    gz_stream *s;
{
    if (s->z_eof) return EOF;
    if (s->stream.avail_in == 0) {
      s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
      if (s->stream.avail_in == 0) {
          s->z_eof = 1;
          if (ferror(s->file)) s->z_err = Z_ERRNO;
          return EOF;
      }
      s->stream.next_in = s->inbuf;
    }
    s->stream.avail_in--;
    return *(s->stream.next_in)++;
}

local uLong getLong (s)
    gz_stream *s;
{
    uLong x = (uLong)getByte(s);
    int c;

    x += ((uLong)getByte(s))<<8;
    x += ((uLong)getByte(s))<<16;
    c = getByte(s);
    if (c == EOF) s->z_err = Z_DATA_ERROR;
    x += ((uLong)c)<<24;
    return x;
}

local void check_header(s)
    gz_stream *s;
{
    int method; /* method byte */
    int flags;  /* flags byte */
    uInt len;
    int c;

    /* Check the gzip magic header */
    if (!s->verified) {
      s->verified = 1;
        for (len = 0; len < 2; len++) {
          c = getByte(s);
          if (c != gz_magic[len]) {
              if (len != 0) s->stream.avail_in++, s->stream.next_in--;
              if (c != EOF) {
                s->stream.avail_in++, s->stream.next_in--;
                s->transparent = 1;
              }
              s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
              return;
          }
        }
    }
    method = getByte(s);
    flags = getByte(s);
    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
      s->z_err = Z_DATA_ERROR;
      return;
    }

    /* Discard time, xflags and OS code: */
    for (len = 0; len < 6; len++) (void)getByte(s);

    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
      len  =  (uInt)getByte(s);
      len += ((uInt)getByte(s))<<8;
      /* len is garbage if EOF but the loop below will quit anyway */
      while (len-- != 0 && getByte(s) != EOF) ;
    }
    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
      while ((c = getByte(s)) != 0 && c != EOF) ;
    }
    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
      while ((c = getByte(s)) != 0 && c != EOF) ;
    }
    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
      for (len = 0; len < 2; len++) (void)getByte(s);
    }
    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
}

local int destroy (s)
    gz_stream *s;
{
    int err = Z_OK;

    if (!s) return Z_STREAM_ERROR;

    TRYFREE(s->msg);

    if (s->stream.state != NULL)
          err = inflateEnd(&(s->stream));
    if (s->z_err < 0) err = s->z_err;

    TRYFREE(s->inbuf);
    TRYFREE(s->outbuf);
    TRYFREE(s->path);
    TRYFREE(s);
    return err;
}

gzFile gzfopen (fp, mode)
    FILE* fp;
    const char *mode;
{
    int err;
    gz_stream *s;

    if (!mode) return Z_NULL;

    s = (gz_stream *)ALLOC(sizeof(gz_stream));
    if (!s) return Z_NULL;

    s->stream.zalloc = (alloc_func)0;
    s->stream.zfree = (free_func)0;
    s->stream.opaque = (voidpf)0;
    s->stream.next_in = s->inbuf = Z_NULL;
    s->stream.next_out = s->outbuf = Z_NULL;
    s->stream.avail_in = s->stream.avail_out = 0;
    s->file = NULL;
    s->z_err = Z_OK;
    s->z_eof = 0;
    s->msg = NULL;
    s->transparent = 0;
    s->verified = 0;

    s->path = "/dev/stdin";
    if (s->path == NULL) {
        return destroy(s), (gzFile)Z_NULL;
    }

    s->mode = 0;
    do {
        if (*mode == 'r')
        s->mode = 'r';
      else if (*mode == 'v')
        s->verified = 1;
    } while (*mode++);
    if (s->mode != 'r')
        return destroy(s), (gzFile)Z_NULL;
    s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
    err = inflateInit2(&(s->stream), -MAX_WBITS, ZLIB_VERSION, sizeof(z_stream));
    if (err != Z_OK || s->inbuf == Z_NULL)
        return destroy(s), (gzFile)Z_NULL;
    s->stream.avail_out = Z_BUFSIZE;
    s->file = fp;
    check_header(s); /* skip the .gz header */
    s->startpos = (ftell(s->file) - s->stream.avail_in);
    return (gzFile)s;
}

int ZEXPORT gzread (file, buf, len)
    gzFile file;
    voidp buf;
    unsigned len;
{
    gz_stream *s = (gz_stream*)file;
    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */

    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;

    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */

    next_out = (Byte*)buf;
    s->stream.next_out = (Bytef*)buf;
    s->stream.avail_out = len;

    while (s->stream.avail_out != 0) {

      if (s->transparent) {
          /* Copy first the lookahead bytes: */
          uInt n = s->stream.avail_in;
          if (n > s->stream.avail_out) n = s->stream.avail_out;
          if (n > 0) {
            zmemcpy(s->stream.next_out, s->stream.next_in, n);
            next_out += n;
            s->stream.next_out = next_out;
            s->stream.next_in   += n;
            s->stream.avail_out -= n;
            s->stream.avail_in  -= n;
          }
          if (s->stream.avail_out > 0) {
            s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
                                   s->file);
          }
          len -= s->stream.avail_out;
          s->stream.total_in  += (uLong)len;
          s->stream.total_out += (uLong)len;
            if (len == 0) s->z_eof = 1;
          return (int)len;
      }
        if (s->stream.avail_in == 0 && !s->z_eof) {

            s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
            if (s->stream.avail_in == 0) {
                s->z_eof = 1;
            if (ferror(s->file)) {
                s->z_err = Z_ERRNO;
                break;
            }
            }
            s->stream.next_in = s->inbuf;
        }
        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);

      if (s->z_err < 0) return -1;
      if (s->z_err == Z_STREAM_END) {
          (void)getLong(s);
          {
              (void)getLong(s);
            check_header(s);
            if (s->z_err == Z_OK) {
                uLong total_in = s->stream.total_in;
                uLong total_out = s->stream.total_out;

                inflateReset(&(s->stream));
                s->stream.total_in = total_in;
                s->stream.total_out = total_out;
            }
            else
                s->z_err = Z_STREAM_END;
          }
      }
      if (s->z_err != Z_OK || s->z_eof) break;
    }
    return (int)(len - s->stream.avail_out);
}

#endif /* _GUNZIP_H */

#undef      local

/* === ratz.c === */

#include <sys/stat.h>

#ifndef S_IRUSR
#define S_IRUSR         0400
#endif
#ifndef S_IWUSR
#define S_IWUSR         0200
#endif
#ifndef S_IXUSR
#define S_IXUSR         0100
#endif
#ifndef S_IRGRP
#define S_IRGRP         0040
#endif
#ifndef S_IWGRP
#define S_IWGRP         0020
#endif
#ifndef S_IXGRP
#define S_IXGRP         0010
#endif
#ifndef S_IROTH
#define S_IROTH         0004
#endif
#ifndef S_IWOTH
#define S_IWOTH         0002
#endif
#ifndef S_IXOTH
#define S_IXOTH         0001
#endif

/*
 * Standard Archive Format
 * USTAR - Uniform Standard Tape ARchive
 */

#define TBLOCK          512
#define NAMSIZ          100
#define PFXSIZ          155

#define TMODLEN         8
#define TUIDLEN         8
#define TGIDLEN         8
#define TSIZLEN         12
#define TMTMLEN         12
#define TCKSLEN         8

#define TMAGIC          "ustar"           /* ustar and a null           */
#define TMAGLEN         6
#define TVERSION  "00"        /* 00 and no null       */
#define TVERSLEN  2
#define TUNMLEN         32
#define TGNMLEN         32
#define TDEVLEN         8
#define TPADLEN         12

/*
 * values used in typeflag field
 */

#define REGTYPE         '0'         /* regular file               */
#define AREGTYPE  0           /* alternate REGTYPE          */
#define LNKTYPE         '1'         /* hard link                  */
#define SYMTYPE         '2'         /* soft link                  */
#define CHRTYPE         '3'         /* character special          */
#define BLKTYPE         '4'         /* block special        */
#define DIRTYPE         '5'         /* directory                  */
#define FIFOTYPE  '6'         /* FIFO special               */
#define CONTTYPE  '7'         /* reserved             */
#define SOKTYPE         '8'         /* socket -- reserved         */
#define VERTYPE         'V'         /* version -- reserved        */
#define EXTTYPE         'x'         /* extended header -- reserved      */

/*
 * bits used in mode field
 */

#define TSUID           04000       /* set uid on exec            */
#define TSGID           02000       /* set gid on exec            */
#define TSVTX           01000       /* sticky bit -- reserved     */

/*
 * file permissions
 */

#define TUREAD          00400       /* read by owner        */
#define TUWRITE         00200       /* write by owner       */
#define TUEXEC          00100       /* execute by owner           */
#define TGREAD          00040       /* read by group        */
#define TGWRITE         00020       /* execute by group           */
#define TGEXEC          00010       /* write by group       */
#define TOREAD          00004       /* read by other        */
#define TOWRITE         00002       /* write by other       */
#define TOEXEC          00001       /* execute by other           */

#define TAR_SUMASK      ((1L<<(TCKSLEN-1)*3)-1)

typedef struct
{
      char        name[NAMSIZ];
      char        mode[TMODLEN];
      char        uid[TUIDLEN];
      char        gid[TGIDLEN];
      char        size[TSIZLEN];
      char        mtime[TMTMLEN];
      char        chksum[TCKSLEN];
      char        typeflag;
      char        linkname[NAMSIZ];
      char        magic[TMAGLEN];
      char        version[TVERSLEN];
      char        uname[TUNMLEN];
      char        gname[TGNMLEN];
      char        devmajor[TDEVLEN];
      char        devminor[TDEVLEN];
      char        prefix[PFXSIZ];
      char        pad[TPADLEN];
} Header_t;

static struct
{
      char*       id;
      unsigned long     blocks;
      unsigned long     files;
} state;

#if !_PACKAGE_ast

static void
usage()
{
      fprintf(stderr, "Usage: %s [-clmntvV] < input.tgz\n", state.id);
      exit(2);
}

#endif

/*
 * the X/Open dd EBCDIC table
 */

static const unsigned char a2e[] =
{
      0000,0001,0002,0003,0067,0055,0056,0057,
      0026,0005,0045,0013,0014,0015,0016,0017,
      0020,0021,0022,0023,0074,0075,0062,0046,
      0030,0031,0077,0047,0034,0035,0036,0037,
      0100,0132,0177,0173,0133,0154,0120,0175,
      0115,0135,0134,0116,0153,0140,0113,0141,
      0360,0361,0362,0363,0364,0365,0366,0367,
      0370,0371,0172,0136,0114,0176,0156,0157,
      0174,0301,0302,0303,0304,0305,0306,0307,
      0310,0311,0321,0322,0323,0324,0325,0326,
      0327,0330,0331,0342,0343,0344,0345,0346,
      0347,0350,0351,0255,0340,0275,0232,0155,
      0171,0201,0202,0203,0204,0205,0206,0207,
      0210,0211,0221,0222,0223,0224,0225,0226,
      0227,0230,0231,0242,0243,0244,0245,0246,
      0247,0250,0251,0300,0117,0320,0137,0007,
      0040,0041,0042,0043,0044,0025,0006,0027,
      0050,0051,0052,0053,0054,0011,0012,0033,
      0060,0061,0032,0063,0064,0065,0066,0010,
      0070,0071,0072,0073,0004,0024,0076,0341,
      0101,0102,0103,0104,0105,0106,0107,0110,
      0111,0121,0122,0123,0124,0125,0126,0127,
      0130,0131,0142,0143,0144,0145,0146,0147,
      0150,0151,0160,0161,0162,0163,0164,0165,
      0166,0167,0170,0200,0212,0213,0214,0215,
      0216,0217,0220,0152,0233,0234,0235,0236,
      0237,0240,0252,0253,0254,0112,0256,0257,
      0260,0261,0262,0263,0264,0265,0266,0267,
      0270,0271,0272,0273,0274,0241,0276,0277,
      0312,0313,0314,0315,0316,0317,0332,0333,
      0334,0335,0336,0337,0352,0353,0354,0355,
      0356,0357,0372,0373,0374,0375,0376,0377,
};

/*
 * the X/Open dd IBM table
 */

static const unsigned char a2i[] =
{
      0000,0001,0002,0003,0067,0055,0056,0057,
      0026,0005,0045,0013,0014,0015,0016,0017,
      0020,0021,0022,0023,0074,0075,0062,0046,
      0030,0031,0077,0047,0034,0035,0036,0037,
      0100,0132,0177,0173,0133,0154,0120,0175,
      0115,0135,0134,0116,0153,0140,0113,0141,
      0360,0361,0362,0363,0364,0365,0366,0367,
      0370,0371,0172,0136,0114,0176,0156,0157,
      0174,0301,0302,0303,0304,0305,0306,0307,
      0310,0311,0321,0322,0323,0324,0325,0326,
      0327,0330,0331,0342,0343,0344,0345,0346,
      0347,0350,0351,0255,0340,0275,0137,0155,
      0171,0201,0202,0203,0204,0205,0206,0207,
      0210,0211,0221,0222,0223,0224,0225,0226,
      0227,0230,0231,0242,0243,0244,0245,0246,
      0247,0250,0251,0300,0117,0320,0241,0007,
      0040,0041,0042,0043,0044,0025,0006,0027,
      0050,0051,0052,0053,0054,0011,0012,0033,
      0060,0061,0032,0063,0064,0065,0066,0010,
      0070,0071,0072,0073,0004,0024,0076,0341,
      0101,0102,0103,0104,0105,0106,0107,0110,
      0111,0121,0122,0123,0124,0125,0126,0127,
      0130,0131,0142,0143,0144,0145,0146,0147,
      0150,0151,0160,0161,0162,0163,0164,0165,
      0166,0167,0170,0200,0212,0213,0214,0215,
      0216,0217,0220,0232,0233,0234,0235,0236,
      0237,0240,0252,0253,0254,0255,0256,0257,
      0260,0261,0262,0263,0264,0265,0266,0267,
      0270,0271,0272,0273,0274,0275,0276,0277,
      0312,0313,0314,0315,0316,0317,0332,0333,
      0334,0335,0336,0337,0352,0353,0354,0355,
      0356,0357,0372,0373,0374,0375,0376,0377,
};

/*
 * the mvs OpenEdition EBCDIC table
 */

static const unsigned char a2o[] =
{
      0000,0001,0002,0003,0067,0055,0056,0057,
      0026,0005,0025,0013,0014,0015,0016,0017,
      0020,0021,0022,0023,0074,0075,0062,0046,
      0030,0031,0077,0047,0034,0035,0036,0037,
      0100,0132,0177,0173,0133,0154,0120,0175,
      0115,0135,0134,0116,0153,0140,0113,0141,
      0360,0361,0362,0363,0364,0365,0366,0367,
      0370,0371,0172,0136,0114,0176,0156,0157,
      0174,0301,0302,0303,0304,0305,0306,0307,
      0310,0311,0321,0322,0323,0324,0325,0326,
      0327,0330,0331,0342,0343,0344,0345,0346,
      0347,0350,0351,0255,0340,0275,0137,0155,
      0171,0201,0202,0203,0204,0205,0206,0207,
      0210,0211,0221,0222,0223,0224,0225,0226,
      0227,0230,0231,0242,0243,0244,0245,0246,
      0247,0250,0251,0300,0117,0320,0241,0007,
      0040,0041,0042,0043,0044,0045,0006,0027,
      0050,0051,0052,0053,0054,0011,0012,0033,
      0060,0061,0032,0063,0064,0065,0066,0010,
      0070,0071,0072,0073,0004,0024,0076,0377,
      0101,0252,0112,0261,0237,0262,0152,0265,
      0273,0264,0232,0212,0260,0312,0257,0274,
      0220,0217,0352,0372,0276,0240,0266,0263,
      0235,0332,0233,0213,0267,0270,0271,0253,
      0144,0145,0142,0146,0143,0147,0236,0150,
      0164,0161,0162,0163,0170,0165,0166,0167,
      0254,0151,0355,0356,0353,0357,0354,0277,
      0200,0375,0376,0373,0374,0272,0256,0131,
      0104,0105,0102,0106,0103,0107,0234,0110,
      0124,0121,0122,0123,0130,0125,0126,0127,
      0214,0111,0315,0316,0313,0317,0314,0341,
      0160,0335,0336,0333,0334,0215,0216,0337,
};

/*
 * ascii text vs. control
 */

static const unsigned char ascii_text[] =
{
      0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};

static int
block(fp, gz, buf)
FILE* fp;
gzFile      gz;
char* buf;
{
      int   r;

      if (gz)
            r = gzread(gz, buf, sizeof(Header_t)) == sizeof(Header_t);
      else
            r = fread(buf, sizeof(Header_t), 1, fp) == 1;
      if (r)
            state.blocks++;
      return r;
}

static int
skip(fp, gz, buf, n)
FILE*       fp;
gzFile            gz;
char*       buf;
unsigned long     n;
{
      while (n > 0)
      {
            if (!block(fp, gz, buf))
            {
                  fprintf(stderr, "%s: unexpected EOF\n", state.id);
                  return 1;
            }
            if (n <= sizeof(Header_t))
                  break;
            n -= sizeof(Header_t);
      }
      return 0;
}

static unsigned long
number(s)
register char*    s;
{
      unsigned long     n = 0;

      while (*s == ' ')
            s++;
      while (*s >= '0' && *s <= '7')
            n = (n << 3) + (*s++ - '0');
      return n;
}

#if defined(_SEAR_SEEK) || defined(_SEAR_EXEC)

#ifndef PATH_MAX
#define PATH_MAX  256
#endif

#define EXIT(n)   return(sear_exec((char*)0),(n))

static int  sear_stdin;
static char*      sear_tmp;
static char sear_buf[PATH_MAX];

static int
sear_seek(off_t offset, int tmp)
{
      int   n;
      char  cmd[PATH_MAX];

      GetModuleFileName(NULL, cmd, sizeof(cmd));
      sear_stdin = dup(0);
      close(0);
      if (open(cmd, O_BINARY|O_RDONLY) || lseek(0, offset, 0) != offset)
      {
            fprintf(stderr, "%s: %s: cannot seek to data offset\n", state.id, cmd);
            return -1;
      }
      if (tmp)
      {
            if ((n = GetTempPath(sizeof(cmd), cmd)) <= 0 || n > sizeof(cmd))
            {
                  fprintf(stderr, "%s: cannot determine temporary directory path\n", state.id);
                  return -1;
            }
            if (!GetTempFileName(cmd, "SEA", 0, sear_buf))
            {
                  fprintf(stderr, "%s: cannot determine temporary file path\n", state.id);
                  return -1;
            }
            sear_tmp = sear_buf;
            if (!DeleteFile(sear_tmp))
            {
                  fprintf(stderr, "%s: %s: cannot initialize temporary directory\n", state.id, sear_tmp);
                  return -1;
            }
            if (!CreateDirectory(sear_tmp, NULL))
            {
                  fprintf(stderr, "%s: %s: cannot create temporary directory\n", state.id, sear_tmp);
                  return -1;
            }
            if (!SetCurrentDirectory(sear_tmp))
            {
                  fprintf(stderr, "%s: %s: cannot cd to temporary directory\n", state.id, sear_tmp);
                  return -1;
            }
      }
      return 0;
}

/*
 * remove dir and its subdirs
 */

static void
sear_rm_r(char* dir)
{
      WIN32_FIND_DATA   info;
      HANDLE            hp;

      if (!SetCurrentDirectory(dir))
            return;
      if ((hp = FindFirstFile("*.*", &info)) != INVALID_HANDLE_VALUE)
            do
            {
                  if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                  {
                        if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
                              SetFileAttributes(info.cFileName, info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
                        DeleteFile(info.cFileName);
                  }
                  else if (info.cFileName[0] != '.' || info.cFileName[1] != 0 && (info.cFileName[1] != '.' || info.cFileName[2] != 0))
                        sear_rm_r(info.cFileName);
            } while(FindNextFile(hp, &info));
      FindClose(hp);
      if (!SetCurrentDirectory(".."))
            return;
      RemoveDirectory(dir);
}

/*
 * system(3) without PATH search that should work on all windows variants
 */

static int
sear_system(const char* command)
{
      PROCESS_INFORMATION     pinfo;
      STARTUPINFO       sinfo;
      char*             cp;
      char              path[PATH_MAX];
      int               n = *command == '"';

      strncpy(path, &command[n], PATH_MAX - 4);
      n = n ? '"' : ' ';
      for (cp = path; *cp; *cp++)
            if (*cp == n)
                  break;
      *cp = 0;
      if (GetFileAttributes(path)==0xffffffff && GetLastError()==ERROR_FILE_NOT_FOUND)
            strcpy(cp, ".exe");
      ZeroMemory(&sinfo, sizeof(sinfo));
      if (CreateProcess(path, (char*)command, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo))
      {
            CloseHandle(pinfo.hThread);
            WaitForSingleObject(pinfo.hProcess, INFINITE);
            if (!GetExitCodeProcess(pinfo.hProcess, &n))
                  n = 1;
            CloseHandle(pinfo.hProcess);
      }
      else
            n = GetLastError() == ERROR_FILE_NOT_FOUND ? 127 : 126;
      return n;
}

/*
 * execute cmd, chdir .., and remove sear_tmp
 */

static int
sear_exec(const char* cmd)
{
      int         r;

      fflush(stdout);
      fflush(stderr);
      if (sear_tmp)
      {
            close(0);
            dup(sear_stdin);
            close(sear_stdin);
            r = cmd ? sear_system(cmd) : 1;
            sear_rm_r(sear_tmp);
      }
      else
            r = cmd ? 0 : 1;
      return r;
}

#else

#define EXIT(n)   return(n)

#endif

int
main(argc, argv)
int   argc;
char**      argv;
{
      register int            c;
      register char*          s;
      register char*          t;
      register char*          e;
      unsigned long           n;
      unsigned long           m;
      const unsigned char*    a2x;
      int               clear;
      int               list;
      int               local;
      int               meter;
      int               unzip;
      int               verbose;
      unsigned int            mode;
      unsigned long           total;
      off_t             pos;
      gzFile                  gz;
      FILE*             fp;
      Header_t          header;
      unsigned char           num[4];
      char              path[sizeof(header.prefix) + sizeof(header.name) + 4];
      char              buf[sizeof(header)];
#if defined(_SEAR_OPTS)
      char*             opts[4];
#endif

      setmode(0, O_BINARY);
      setmode(1, O_BINARY);
      clear = 0;
      list = 0;
      local = 0;
      meter = 0;
      unzip = 0;
      verbose = 0;
      if (s = *argv)
      {
            t = s;
            while (*s)
                  if (*s++ == '/')
                        t = s;
            if (!strcmp(t, "gunzip"))
                  unzip = 1;
            state.id = t;
      }
      else
            state.id = "ratz";
      switch ('~')
      {
      case 0241:
            switch ('\n')
            {
            case 0025:
                  a2x = a2o;
                  break;
            default:
                  a2x = a2e;
                  break;
            }
            break;
      case 0137:
            a2x = a2i;
            break;
      default:
            a2x = 0;
            break;
      }
#if defined(_SEAR_OPTS)
      opts[0] = argv[0];
      opts[1] = _SEAR_OPTS;
      opts[2] = argv[1];
      opts[3] = 0;
      argv = opts;
#endif
#if _PACKAGE_ast
      error_info.id = state.id;
      for (;;)
      {
            switch (optget(argv, usage))
            {
            case 'c':
                  unzip = 1;
                  continue;
            case 'l':
                  local = 1;
                  continue;
            case 'm':
                  meter = 1;
                  continue;
            case 'n':
                  a2x = 0;
                  continue;
            case 't':
                  list = 1;
                  continue;
            case 'v':
                  verbose = 1;
                  continue;
            case 'V':
                  sfprintf(sfstdout, "%s\n", id + 10);
                  return 0;
            case '?':
                  error(ERROR_USAGE|4, "%s", opt_info.arg);
                  continue;
            case ':':
                  error(2, "%s", opt_info.arg);
                  continue;
            }
            break;
      }
      if (error_info.errors)
            error(ERROR_USAGE|4, "%s", optusage(NiL));
      argv += opt_info.index;
#else
      while ((s = *++argv) && *s == '-' && *(s + 1))
      {
            if (*(s + 1) == '-')
            {
                  if (!*(s + 2))
                  {
                        argv++;
                        break;
                  }
                  usage();
                  break;
            }
            for (;;)
            {
                  switch (c = *++s)
                  {
                  case 0:
                        break;
                  case 'c':
                        unzip = 1;
                        continue;
                  case 'l':
                        local = 1;
                        continue;
                  case 'm':
                        meter = 1;
                        continue;
                  case 'n':
                        a2x = 0;
                        continue;
                  case 't':
                        list = 1;
                        continue;
                  case 'v':
                        verbose = 1;
                        continue;
                  case 'V':
                        fprintf(stdout, "%s\n", id + 10);
                        return 0;
                  default:
                        fprintf(stderr, "%s: -%c: unknown option\n", state.id, c);
                        /*FALLTHROUGH*/
                  case '?':
                        usage();
                        break;
                  }
                  break;
            }
      }
#endif

#if defined(_SEAR_SEEK)
      if (sear_seek((off_t)_SEAR_SEEK, !list))
      {
            Sleep(5 * 1000);
            return 1;
      }
#endif

      /*
       * commit on the first gzip magic char
       */

      if ((c = getchar()) == EOF)
            EXIT(0);
      ungetc(c, stdin);
      if (c != gz_magic[0])
            gz = 0;
      else if (!(gz = gzfopen(stdin, FOPEN_READ)))
      {
            fprintf(stderr, "%s: gunzip open error\n", state.id);
            EXIT(1);
      }
      if (unzip)
      {
            if (!gz)
            {
                  fprintf(stderr, "%s: not a gzip file\n", state.id);
                  EXIT(1);
            }
            while ((c = gzread(gz, buf, sizeof(buf))) > 0)
                  if (fwrite(buf, c, 1, stdout) != 1)
                  {
                        fprintf(stderr, "%s: write error\n", state.id);
                        EXIT(1);
                  }
            if (c < 0)
            {
                  fprintf(stderr, "%s: read error\n", state.id);
                  EXIT(1);
            }
            if (fflush(stdout))
            {
                  fprintf(stderr, "%s: flush error\n", state.id);
                  EXIT(1);
            }
            EXIT(0);
      }
      if (meter)
      {
            if ((pos = lseek(0, (off_t)0, SEEK_CUR)) < 0)
                  meter = 0;
            else
            {
                  if (lseek(0, (off_t)(-4), SEEK_END) < 0 || read(0, num, 4) != 4)
                        meter = 0;
                  else if (!(total = ((num[0]|(num[1]<<8)|(num[2]<<16)|(num[3]<<24)) + sizeof(Header_t) - 1) / sizeof(Header_t)))
                        total = 1;
                  lseek(0, pos, SEEK_SET);
            }
      }

      /*
       * loop on all the header blocks
       */

      while (block(stdin, gz, (char*)&header))
      {
            /*
             * last 2 blocks are NUL
             */

            if (!*header.name)
                  break;

            /*
             * verify the checksum
             */

            s = header.chksum;
            e = header.chksum + sizeof(header.chksum);
            if (a2x)
            {
                  for (; s < e; s++)
                        *s = a2x[*(unsigned char*)s];
                  s = header.chksum;
            }
            n = number(s) & TAR_SUMASK;
            while (s < e)
                  *s++ = 040;
            m = 0;
            s = (char*)&header;
            e = (char*)&header + sizeof(header);
            while (s < e)
                  m += *(unsigned char*)s++;
            m &= TAR_SUMASK;
            if (m != n)
            {
                  if (state.files)
                        fprintf(stderr, "%s: archive corrupted\n", state.id);
                  else
                        fprintf(stderr, "%s: not a tar archive\n", state.id);
                  fprintf(stderr, "check sum %lu != %lu\n", m, n);
                  EXIT(1);
            }

            /*
             * convert to the native charset
             */

            if (a2x)
                  for (e = (s = (char*)&header) + sizeof(header); s < e; s++)
                        *s = a2x[*(unsigned char*)s];

            /*
             * get the pathname, type and size
             */

            state.files++;
            t = path;
            if (!strncmp(header.magic, TMAGIC, sizeof(header.magic)) && *header.prefix)
            {
                  s = header.prefix;
                  e = header.prefix + sizeof(header.prefix);
                  while (s < e && (c = *s++))
                        *t++ = c;
                  *t++ = '/';
            }
            s = header.name;
            e = header.name + sizeof(header.name);
            while (s < e && (c = *s++))
                  *t++ = c;
            *t = 0;

            /*
             * verify the dir prefix
             */

            t = 0;
            s = path;
            while (*s)
                  if (*s++ == '/')
                        t = s;
            if (t)
            {
                  *--t = 0;
                  if (!list && access(path, 0))
                  {
                        s = path;
                        do
                        {
                              if (!(c = *s) || c == '/')
                              {
                                    *s = 0;
                                    if (access(path, 0) && mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH))
                                    {
                                          fprintf(stderr, "%s: %s: cannot create directory\n", state.id, path);
                                          EXIT(1);
                                    }
                                    *s = c;
                              }
                        } while (*s++);
                  }
                  if (*(t + 1))
                        *t = '/';
                  else
                        header.typeflag = DIRTYPE;
            }

            /*
             * check for non-local paths
             */

            if (local && (path[0] == '/' || path[0] == '.' && path[1] == '.' && (!path[2] || path[2] == '/')))
            {
                  fprintf(stderr, "%s: %s: non-local path rejected", state.id, path);
                  if ((header.typeflag == REGTYPE || header.typeflag == AREGTYPE) && (n = number(header.size)))
                        while (n > 0)
                        {
                              if (!block(stdin, gz, buf))
                              {
                                    fprintf(stderr, "%s: unexpected EOF\n", state.id);
                                    EXIT(1);
                              }
                              if (n <= sizeof(header))
                                    break;
                              n -= sizeof(header);
                        }
                  continue;
            }

            /*
             * create and grab the data
             */

            n = number(header.mode);
            mode = 0;
            if (n & TUREAD)
                  mode |= S_IRUSR;
            if (n & TUWRITE)
                  mode |= S_IWUSR;
            if (n & TUEXEC)
                  mode |= S_IXUSR;
            if (n & TGREAD)
                  mode |= S_IRGRP;
            if (n & TGWRITE)
                  mode |= S_IWGRP;
            if (n & TGEXEC)
                  mode |= S_IXGRP;
            if (n & TOREAD)
                  mode |= S_IROTH;
            if (n & TOWRITE)
                  mode |= S_IWOTH;
            if (n & TOEXEC)
                  mode |= S_IXOTH;
            if (list || meter)
            {
                  if (meter)
                  {
                        int   i;
                        int   j;
                        int   k;
                        int   n;
                        int   p;
                        char  bar[METER_parts + 1];

                        for (s = path; *s; s++)
                              if (s[0] == ' ' && s[1] == '-' && s[2] == '-' && s[3] == ' ')
                                    break;
                        if (*s)
                        {
                              if (clear)
                              {
                                    fprintf(stderr, "%*s", clear, "\r");
                                    clear = 0;
                              }
                              fprintf(stderr, "\n%s\n\n", path);
                        }
                        else
                        {
                              n = strlen(s = path);
                              p = (state.blocks * 100) / total;
                              if (n > (METER_width - METER_parts - 1))
                              {
                                    s += n - (METER_width - METER_parts - 1);
                                    n = METER_width - METER_parts - 1;
                              }
                              j = n + METER_parts + 2;
                              if (!clear)
                                    clear = j + 5;
                              if ((k = clear - j - 5) < 0)
                                    k = 0;
                              if ((i = (p / (100 / METER_parts))) >= sizeof(bar))
                                    i = sizeof(bar) - 1;
                              n = 0;
                              while (n < i)
                                    bar[n++] = '*';
                              while (n < sizeof(bar) - 1)
                                    bar[n++] = ' ';
                              bar[n] = 0;
                              clear = fprintf(stderr, "%02d%% |%s| %s%*s", p, bar, s, k, "\r");
                        }
                  }
                  else
                  {
                        if (verbose)
                        {
                              switch (header.typeflag)
                              {
                              case REGTYPE:
                              case AREGTYPE:
                                    c = '-';
                                    break;
                              case DIRTYPE:
                                    c = 'd';
                                    break;
                              case LNKTYPE:
                                    c = 'h';
                                    break;
                              case SYMTYPE:
                                    c = 'l';
                                    break;
                              default:
                                    c = '?';
                                    break;
                              }
                              printf("%c", c);
                              m = 0400; 
                              while (m)
                              {
                                    printf("%c", (n & m) ? 'r' : '-');
                                    m >>= 1;
                                    printf("%c", (n & m) ? 'w' : '-');
                                    m >>= 1;
                                    printf("%c", (n & m) ? 'x' : '-');
                                    m >>= 1;
                              }
                              printf(" %10lu ", number(header.size));
                        }
                        switch (header.typeflag)
                        {
                        case LNKTYPE:
                              printf("%s == %s\n", path, header.linkname);
                              break;
                        case SYMTYPE:
                              printf("%s => %s\n", path, header.linkname);
                              break;
                        default:
                              printf("%s\n", path);
                              break;
                        }
                  }
                  if (list)
                  {
                        if (skip(stdin, gz, buf, number(header.size)))
                              EXIT(1);
                        continue;
                  }
            }
            else if (verbose)
                  printf("%s\n", path);
            switch (header.typeflag)
            {
            case REGTYPE:
            case AREGTYPE:
                  while (!(fp = fopen(path, FOPEN_WRITE)))
                        if (unlink(path))
                        {
                              fprintf(stderr, "%s: warning: %s: cannot create file\n", state.id, path);
                              break;
                        }
                  n = number(header.size);
                  c = a2x ? 0 : -1;
                  while (n > 0)
                  {
                        if (!block(stdin, gz, buf))
                        {
                              fprintf(stderr, "%s: unexpected EOF\n", state.id);
                              EXIT(1);
                        }
                        switch (c)
                        {
                        case 0:
                              if ((m = n) < 4)
                              {
                                    for (e = (s = buf) + m; s < e; s++)
                                          if (a2x[*(unsigned char*)s] != '\n')
                                                break;
                              }
                              else
                              {
                                    if (m > 256)
                                          m = 256;
                                    for (e = (s = buf) + m; s < e; s++)
                                          if (!ascii_text[*(unsigned char*)s])
                                                break;
                              }
                              if (s < e)
                              {
                                    c = -1;
                                    break;
                              }
                              c = 1;
                              /*FALLTHROUGH*/
                        case 1:
                              for (e = (s = buf) + sizeof(header); s < e; s++)
                                    *s = a2x[*(unsigned char*)s];
                              break;
                        }
                        if (fp && fwrite(buf, n > sizeof(header) ? sizeof(header) : n, 1, fp) != 1)
                        {
                              fprintf(stderr, "%s: %s: write error\n", state.id, path);
                              EXIT(1);
                        }
                        if (n <= sizeof(header))
                              break;
                        n -= sizeof(header);
                  }
                  if (fp && fclose(fp))
                  {
                        fprintf(stderr, "%s: %s: write error\n", state.id, path);
                        EXIT(1);
                  }
                  break;
            case DIRTYPE:
                  if (access(path, 0) && mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH))
                  {
                        fprintf(stderr, "%s: %s: cannot create directory\n", state.id, path);
                        EXIT(1);
                  }
                  break;
            case SYMTYPE:
#if defined(S_IFLNK) || defined(S_ISLNK)
                  while (symlink(header.linkname, path))
                        if (unlink(path))
                        {
                              fprintf(stderr, "%s: %s: cannot symlink to %s\n", state.id, path, header.linkname);
                              EXIT(1);
                        }
                  continue;
#endif
#if !_WIN32 || _WINIX
            case LNKTYPE:
                  while (link(header.linkname, path))
                        if (unlink(path))
                        {
                              fprintf(stderr, "%s: %s: cannot link to %s\n", state.id, path, header.linkname);
                              EXIT(1);
                        }
                  continue;
#endif
            default:
                  fprintf(stderr, "%s: %s: file type %c ignored\n", state.id, path, header.typeflag);
                  if (skip(stdin, gz, buf, number(header.size)))
                        EXIT(1);
                  continue;
            }
            if (chmod(path, mode))
                  fprintf(stderr, "%s: %s: cannot change mode to %03o\n", state.id, path, mode);
      }
      if (clear)
            fprintf(stderr, "%*s", clear, "\r");
      if (!state.files)
            fprintf(stderr, "%s: warning: empty archive\n", state.id);
      else if (verbose)
            fprintf(stderr, "%lu file%s, %lu block%s\n", state.files, state.files == 1 ? "" : "s", state.blocks, state.blocks == 1 ? "" : "s");
#if defined(_SEAR_EXEC)
      if (sear_exec(_SEAR_EXEC))
      {
            Sleep(5 * 1000);
            return 1;
      }
#endif
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index