[comp.sources.misc] v08i043: UnZip for Unix

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (09/24/89)

Posting-number: Volume 8, Issue 43
Submitted-by: george@gatech.edu@rebel.UUCP (George M. Sipe)
Archive-name: unzip_gs

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	crc32.c
#	crc32.h
#	unzip.c
#	unzip.doc
# This archive created: Sun Sep 17 15:30:42 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XEnclosed is version 2.0 of UnZip by Samuel H. Smith.  This software
Xcan unarchive any .ZIP file including those created by the recently
Xreleased pkzip version 1.01.  Personally, I prefer zoo for many
Xreasons, but there will be zip archives out there and this can help.
X
XUnfortunately, the software as released is dependent on the TurboC
Xruntime library, the 80x86 byte ordering, and compiler optimization
Xassumptions.  Not very good at all for easy porting to Unix, or for that
Xmatter, any other C compiler/machine combination.  I have made some
Xsignificant improvements to create UnZip 2.0.1 in order to increase
Xportability, to run under Unix, and to compile on PC's under MicroSoft
XC.  This software has NOT been extensively tested, but appears to
Xwork well so far.
X
XThis version will be sent to the author just as soon as I can finally
Xget throught to his BBS.  I had sent him the same improvements for his
Xlast version (1.5) and explained the benefits of not having zillions of
Xmachine specific versions, but to no avail (there are Amiga and other
Xhacks out there - mine should be generally more portable).  Sam's
Xlicence permits this modified distribtion when the source is included,
Xas it is here.
X
XMy changes among other things, perform such tasks as AUTOMATICALLY
Xadjusting operation for any byte-ordering (if HIGH_LOW is defined)
Xand handling C compilers which do not pack structures on 2 byte
Xboundaries (i.e. move 'longint's to the next 4 byte boundary - this
Xis a common, and frequently unstoppable, optimization).
X
X
XGeorge M. Sipe,		       Phone: (404) 447-4731
X537 Lakeshore Drive, Berkeley Lake, GA  30136-3035
XUUCP: ...!{decvax,linus,rutgers}!gatech!rebel!george
SHAR_EOF
fi
if test -f 'crc32.c'
then
	echo shar: "will not over-write existing file 'crc32.c'"
else
sed 's/^X//' << \SHAR_EOF > 'crc32.c'
X/*  --------------------------------------------------------------------  */
X/*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
X/*  code or tables extracted from it, as desired without restriction.     */
X/*                                                                        */
X/*  First, the polynomial itself and its table of feedback terms.  The    */
X/*  polynomial is                                                         */
X/*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
X/*                                                                        */
X/*  Note that we take it "backwards" and put the highest-order term in    */
X/*  the lowest-order bit.  The X^32 term is "implied"; the LSB is the     */
X/*  X^31 term, etc.  The X^0 term (usually shown as "+1") results in      */
X/*  the MSB being 1.                                                      */
X/*                                                                        */
X/*  Note that the usual hardware shift register implementation, which     */
X/*  is what we're using (we're merely optimizing it by doing eight-bit    */
X/*  chunks at a time) shifts bits into the lowest-order term.  In our     */
X/*  implementation, that means shifting towards the right.  Why do we     */
X/*  do it this way?  Because the calculated CRC must be transmitted in    */
X/*  order from highest-order term to lowest-order term.  UARTs transmit   */
X/*  characters in order from LSB to MSB.  By storing the CRC this way,    */
X/*  we hand it to the UART in the order low-byte to high-byte; the UART   */
X/*  sends each low-bit to hight-bit; and the result is transmission bit   */
X/*  by bit from highest- to lowest-order term without requiring any bit   */
X/*  shuffling on our part.  Reception works similarly.                    */
X/*                                                                        */
X/*  The feedback terms table consists of 256, 32-bit entries.  Notes:     */
X/*                                                                        */
X/*      The table can be generated at runtime if desired; code to do so   */
X/*      is shown later.  It might not be obvious, but the feedback        */
X/*      terms simply represent the results of eight shift/xor opera-      */
X/*      tions for all combinations of data and CRC register values.       */
X/*                                                                        */
X/*      The values must be right-shifted by eight bits by the "updcrc"    */
X/*      logic; the shift must be unsigned (bring in zeroes).  On some     */
X/*      hardware you could probably optimize the shift in assembler by    */
X/*      using byte-swap instructions.                                     */
X/*      polynomial $edb88320                                              */
X/*                                                                        */
X/*  --------------------------------------------------------------------  */
X
Xlong crc_32_tab[] = {
X      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
X      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
X      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
X      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
X      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
X      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
X      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
X      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
X      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
X      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
X      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
X      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
X      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
X      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
X      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
X      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
X      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
X      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
X      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
X      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
X      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
X      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
X      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
X      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
X      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
X      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
X      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
X      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
X      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
X      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
X      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
X      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
X      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
X      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
X      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
X      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
X      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
X      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
X      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
X      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
X      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
X      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
X      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
X      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
X      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
X      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
X      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
X      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
X      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
X      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
X      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
X      0x2d02ef8dL
X   };
X
X#ifndef	TURBOC
Xtypedef	unsigned char	byte;
X#endif	/* !TURBOC */
X
X#define UPDCRC32(res,oct) \
X	res=crc_32_tab[(byte)res ^ (byte)oct] ^ ((res >> 8) & 0x00FFFFFFL)
X
X/*
X * Inline assembly version of 32 bit CRC calculation
X * Copyright 1989 Samuel H. Smith
X *
X * You may use this program, or code extracted from it,
X * as desired without restriction.
X *
X */
X
Xextern long crc32val;
X
X/* update running CRC calculation with contents of a buffer */
X
X#ifndef	OLDC
Xvoid UpdateCRC(unsigned char *s, register int len)
X#else
Xvoid UpdateCRC(s, len)
Xunsigned char *s;
Xregister int len;
X#endif	/* OLDC */
X{
X#ifndef	TURBOC
X        while (len--) {
X                UPDCRC32(crc32val, *s++);
X        }
X#else
X        asm     push cx
X        asm     push si
X
X        asm     mov cx,len
X
X        asm     les si,s
X
X        asm     mov dx,crc32val+2
X        asm     mov ax,crc32val
X
XcrcNext:
X        asm     mov bh,al       /* save crc32val[0] */
X
X        asm     mov al,ah       /* (crc32 >> 8) & 0x00ffffff */
X        asm     mov ah,dl
X        asm     mov dl,dh
X        asm     xor dh,dh
X
X        asm     mov bl,es:[si]
X        asm     inc si
X
X        asm     xor bl,bh       /* crcval[0] */
X
X        asm     xor bh,bh
X        asm     shl bx,1
X        asm     shl bx,1
X        asm     xor ax,crc_32_tab[bx]
X        asm     xor dx,crc_32_tab[bx+2]
X
X        asm     loop crcNext
X
X        asm     mov crc32val+2,dx
X        asm     mov crc32val,ax
X        asm     pop si
X        asm     pop cx
X#endif	/* TURBOC */
X}
SHAR_EOF
fi
if test -f 'crc32.h'
then
	echo shar: "will not over-write existing file 'crc32.h'"
else
sed 's/^X//' << \SHAR_EOF > 'crc32.h'
Xlong crc32val;
X
X/* update running CRC calculation with contents of a buffer */
X
X#ifndef	OLDC
Xvoid UpdateCRC(unsigned char *s, register int len);
X#else
Xvoid UpdateCRC();
X#endif	/* OLDC */
SHAR_EOF
fi
if test -f 'unzip.c'
then
	echo shar: "will not over-write existing file 'unzip.c'"
else
sed 's/^X//' << \SHAR_EOF > 'unzip.c'
X
X/*
X * Copyright 1989 Samuel H. Smith;  All rights reserved
X *
X * Do not distribute modified versions without my permission.
X * Do not remove or alter this notice or any other copyright notice.
X * If you use this in your own program you must distribute source code.
X * Do not use any of this in a commercial product.
X *
X */
X
X/*
X * UnZip - A simple zipfile extract utility
X *
X * To compile:
X *      tcc -B -O -Z -G -mc unzip.c	;turbo C 2.0, compact model
X *	cl /O /AC /G0 /W3 -c unzip.	;msc 5.1, compact model
X *	cc -O -DOLDC -Dunix {-DHIGH_LOW} {-DSHORTC} -c unzip.c	;unix pcc
X *
X * Port to Unix and MSC (i.e. "portable version") by George M. Sipe
X * (rebel!george).
X *
X */
X
X#define VERSION  \
X	"UnZip:  Zipfile Extract v2.0.1 of 09-16-89;  (C) 1989 Samuel H. Smith"
X
X#ifdef	SHORTC
X#define	compressed_size		cmpr_sz
X#define	extract_zipfile		ext_zip
X#define	filename		fn
X#define	follower		flwr
X#define	hsize_array_byte	hsz_a_byte
X#define	last_mod_file_date	mod_fdate
X#define	lit_tree_present	lt_present
X#define	maxcodemax		mx_cd_mx
X#define	number_disk_with_start_central_directory ndwsc
X#define	process_central_file_header pcfhdr
X#define	process_end_central_dir	pecdir
X#define	process_headers		proc_hdrs
X#define	total_entries_central_dir tecdir
X#define	version_made_by		v_made_by
X#define	LoadTrees		LdTrees
X#endif	/* SHORTC */
X
Xtypedef unsigned char byte;	/* code assumes UNSIGNED bytes */
Xtypedef long longint;		/* sizeof must be 4 bytes */
Xtypedef unsigned short word;	/* sizeof must be 2 bytes */
Xtypedef char boolean;
X
X#define STRSIZ 256
X
X#include <stdio.h>
X /* this is your standard header for all C compiles */
X
X#ifndef	OLDC
X#include <stdlib.h>
X /* this include defines various standard library prototypes */
X#define	VOIDARG	void		/* function definitions support (void) */
X#else
X#include <ctype.h>
X#define	VOIDARG			/* function definitions support () only */
X#endif	/* OLDC */
X
X
X/*
X * SEE HOST OPERATING SYSTEM SPECIFICS SECTION STARTING NEAR LINE 180
X *
X */
X
X
X/* ----------------------------------------------------------- */
X/*
X * Zipfile layout declarations
X *
X */
X
Xtypedef longint signature_type;
X
X
X#define LOCAL_FILE_HEADER_SIGNATURE  0x04034b50L
X
X
Xtypedef struct local_file_header {
X	word version_needed_to_extract;
X        word general_purpose_bit_flag;
X	word compression_method;
X	word last_mod_file_time;
X	word last_mod_file_date;
X	longint crc32;
X	longint compressed_size;
X        longint uncompressed_size;
X	word filename_length;
X	word extra_field_length;
X} local_file_header;
X
X
X#define CENTRAL_FILE_HEADER_SIGNATURE  0x02014b50L
X
X
Xtypedef struct central_directory_file_header {
X	word version_made_by;
X	word version_needed_to_extract;
X	word general_purpose_bit_flag;
X	word compression_method;
X	word last_mod_file_time;
X	word last_mod_file_date;
X	longint crc32;
X	longint compressed_size;
X	longint uncompressed_size;
X	word filename_length;
X	word extra_field_length;
X	word file_comment_length;
X	word disk_number_start;
X	word internal_file_attributes;
X	longint external_file_attributes;
X	longint relative_offset_local_header;
X} central_directory_file_header;
X
X
X#define END_CENTRAL_DIR_SIGNATURE  0x06054b50L
X
X
Xtypedef struct end_central_dir_record {
X	word number_this_disk;
X#ifndef	TURBOC
X	word num_disk_with_start_cent_dir;
X	word tot_ents_cent_dir_on_this_disk;
X#else
X	word number_disk_with_start_central_directory;
X	word total_entries_central_dir_on_this_disk;
X#endif	/* TURBOC */
X	word total_entries_central_dir;
X	longint size_central_directory;
X	longint offset_start_central_directory;
X	word zipfile_comment_length;
X} end_central_dir_record;
X
X
X
X/* ----------------------------------------------------------- */
X/*
X * input file variables
X *
X */
X
X#define INBUFSIZ 0x2000
Xbyte *inbuf;			/* input file buffer - any size is legal */
Xbyte *inptr;
X
Xint incnt;
Xunsigned bitbuf;
Xint bits_left;
Xboolean zipeof;
X
Xint zipfd;
Xchar zipfn[STRSIZ];
Xlocal_file_header lrec;
X
X#ifdef	HIGH_LOW
Xint w0, w1;			/* word translation indices */
Xint li0, li1, li2, li3;		/* long int translation indices */
X#endif	/* HIGH_LOW */
X
X
X/* ----------------------------------------------------------- */
X/*
X * output stream variables
X *
X */
X
X#define OUTBUFSIZ 0x2000        /* must be 0x2000 or larger for unImplode */
Xbyte *outbuf;                   /* buffer for rle look-back */
Xbyte *outptr;
X
Xlongint outpos;			/* absolute position in outfile */
Xint outcnt;			/* current position in outbuf */
X
Xint outfd;
Xchar filename[STRSIZ];
Xchar extra[STRSIZ];
X
X#define DLE 144
X
X
X/* ----------------------------------------------------------- */
X/*
X * shrink/reduce working storage
X *
X */
X
Xint factor;
Xbyte followers[256][64];
Xbyte Slen[256];
X
X#define max_bits 13
X#define init_bits 9
X#define hsize 8192
X#define first_ent 257
X#define clear 256
X
Xtypedef int hsize_array_integer[hsize+1];
Xtypedef byte hsize_array_byte[hsize+1];
X
Xhsize_array_integer prefix_of;
Xhsize_array_byte suffix_of;
Xhsize_array_byte stack;
X
Xint codesize;
Xint maxcode;
Xint free_ent;
Xint maxcodemax;
Xint offset;
Xint sizex;
X
X
X
X/* ============================================================= */
X/*
X * Host operating system details
X *
X */
X
X#include <string.h>
X /* this include defines strcpy, strcmp, etc. */
X
X#ifndef	TURBOC
X#include <sys/types.h>
X /*
X  * this include file defines
X  *		dev_t (* device type *)
X  * as used in the sys/utime.h and sys/stat.h header files below
X  */
X
X#ifndef	OLDC
X#include <sys/utime.h>
X /*
X  * this include file defines
X  *		struct utimbuf (* utime buffer structure *)
X  *		utime()        (* utime function *)
X  * as used in the set_file_time() function defined below
X  */
X#endif	/* !OLDC */
X#endif	/* !TURBOC */
X
X#ifndef	TURBOC
X#include <time.h>
Xstruct ftime {
X	unsigned ft_tsec: 5;	/* two seconds */
X	unsigned ft_min: 6;	/* minutes */
X	unsigned ft_hour: 5;	/* hours */
X	unsigned ft_day: 5;	/* days */
X	unsigned ft_month: 4;	/* months */
X	unsigned ft_year: 7;	/* years  - 1980 */
X};
X#endif	/* TURBOC */
X#ifndef	OLDC
X#include <io.h>
X#else
X#include <sys/file.h>
X#ifdef	L_SET
X#define	SEEK_SET	L_SET
X#else
X#define	SEEK_SET	0
X#endif	/* L_SET */
X#endif	/* OLDC */
X /*
X  * this include file defines
X  *             struct ftime ...        (* file time/date stamp info *)
X  *             int setftime (int handle, struct ftime *ftimep);
X  *             #define SEEK_CUR  1     (* lseek() modes *)
X  *             #define SEEK_END  2
X  *             #define SEEK_SET  0
X  */
X
X#include <fcntl.h>
X#ifndef	O_BINARY
X#define	O_BINARY	0
X#endif	/* O_BINARY */
X /*
X  * this include file defines
X  *             #define O_BINARY 0x8000  (* no cr-lf translation *)
X  * as used in the open() standard function
X  */
X
X#include <sys/stat.h>
X /*
X  * this include file defines
X  *             #define S_IREAD 0x0100  (* owner may read *)
X  *             #define S_IWRITE 0x0080 (* owner may write *)
X  * as used in the creat() standard function
X  */
X
X/* #undef HIGH_LOW - define externally */
X /*
X  * change 'undef' to 'define' if your machine stores high order bytes in
X  * lower addresses.
X  */
X
Xvoid set_file_time(VOIDARG)
X /*
X  * set the output file date/time stamp according to information from the
X  * zipfile directory record for this file 
X  */
X{
X	union {
X                struct ftime ft;        /* system file time record */
X		struct {
X                        word ztime;     /* date and time words */
X                        word zdate;     /* .. same format as in .ZIP file */
X		} zt;
X	} td;
X
X	/*
X	 * set output file date and time - this is optional and can be
X	 * deleted if your compiler does not easily support setftime() 
X	 */
X#ifdef	TURBOC
X	td.zt.ztime = lrec.last_mod_file_time;
X	td.zt.zdate = lrec.last_mod_file_date;
X
X	setftime(outfd, &td.ft);
X#else
X
X#define leap(y)	 (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
X#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
X
X	static char month_lengths[] =
X		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
X	int day_of_year, year;
X#ifndef	OLDC
X	struct utimbuf times;
X#else
X	struct utimbuf {
X		time_t actime;		/* file accessed time */
X		time_t modtime;		/* file updated time */
X	} times;
X#endif	/* OLDC */
X
X	/*
X	 * this is the standard Unix implementation (also fully
X	 * compatible with MSC)
X	 */
X
X	close(outfd);
X	td.zt.ztime = lrec.last_mod_file_time;
X	td.zt.zdate = lrec.last_mod_file_date;
X	year = td.ft.ft_year + 1980;
X	if (td.ft.ft_month < 1 || td.ft.ft_month > 12 || td.ft.ft_day < 1
X		|| td.ft.ft_day > month_lengths[td.ft.ft_month-1]
X		&& !(td.ft.ft_month == 2 && td.ft.ft_day == 29 && leap (year))
X		|| td.ft.ft_hour > 23 || td.ft.ft_min > 59 ||
X		td.ft.ft_tsec*2 > 59)
X		return;
X	day_of_year = td.ft.ft_day - 1;
X	if (td.ft.ft_month > 2 && leap(year)) ++day_of_year;
X	while (--td.ft.ft_month > 0)
X		day_of_year += month_lengths[td.ft.ft_month - 1];
X	times.modtime = (86400 * (long)(day_of_year + 365 * (year - 1970) 
X		+ nleap (year)) + 3600 * (td.ft.ft_hour-1) + 60 * td.ft.ft_min
X		+ td.ft.ft_tsec*2);
X#ifdef	HAVE_TZ
X	tzset();
X	times.modtime += timezone;
X#endif	/* HAVE_TZ */
X	times.actime = times.modtime;
X	utime(filename, &times);
X#endif	/* !TURBOC */
X}
X
X
Xint create_output_file(VOIDARG)
X /* return non-0 if creat failed */
X{
X	/* create the output file with READ and WRITE permissions */
X	outfd = creat(filename, S_IWRITE | S_IREAD | S_IREAD >> 3
X			| S_IREAD >> 6);
X	if (outfd < 1) {
X		printf("Can't create output: %s\n", filename);
X		return 1;
X	}
X
X	/*
X	 * close the newly created file and reopen it in BINARY mode to
X	 * disable all CR/LF translations 
X	 */
X	close(outfd);
X	outfd = open(filename, O_RDWR | O_BINARY);
X
X	/* write a single byte at EOF to pre-allocate the file */
X#ifdef	tx
X	fsetsize(outfd, lrec.uncompressed_size);
X#endif	/* tx */
X        lseek(outfd, lrec.uncompressed_size - 1L, SEEK_SET);
X	write(outfd, "?", 1);
X	lseek(outfd, 0L, SEEK_SET);
X	return 0;
X}
X
X
Xint open_input_file(VOIDARG)
X /* return non-0 if creat failed */
X{
X	/*
X	 * open the zipfile for reading and in BINARY mode to prevent cr/lf
X	 * translation, which would corrupt the bitstreams 
X	 */
X
X	zipfd = open(zipfn, O_RDONLY | O_BINARY);
X	if (zipfd < 1) {
X		printf("Can't open input file: %s\n", zipfn);
X		return (1);
X	}
X	return 0;
X}
X
X
X#ifdef HIGH_LOW
X
X#ifndef	OLDC
Xvoid swap_bytes(word *wordp)
X#else
Xvoid swap_bytes(wordp)
Xword *wordp;
X#endif	/* OLDC */
X /* convert intel style 'short int' variable to host format */
X{
X	char *charp = (char *) wordp;
X	char temp[2];
X
X	temp[0] = charp[w0];
X	temp[1] = charp[w1];
X	charp[0] = temp[0];
X	charp[1] = temp[1];
X}
X
X#ifndef	OLDC
Xvoid swap_lbytes(longint *longp)
X#else
Xvoid swap_lbytes(longp)
Xlongint *longp;
X#endif	/* OLDC */
X /* convert intel style 'long' variable to host format */
X{
X	char *charp = (char *) longp;
X	char temp[4];
X
X	temp[0] = charp[li0];
X	temp[1] = charp[li1];
X	temp[2] = charp[li2];
X	temp[3] = charp[li3];
X	charp[0] = temp[0];
X	charp[1] = temp[1];
X	charp[2] = temp[2];
X	charp[3] = temp[3];
X}
X
X#endif	/* HIGH_LOW */
X
X
X
X/* ============================================================= */
X
Xint FillBuffer(VOIDARG)
X /* fill input buffer if possible */
X{
X	int readsize;
X
X        if (lrec.compressed_size <= 0)
X		return incnt = 0;
X
X        if (lrec.compressed_size > INBUFSIZ)
X		readsize = INBUFSIZ;
X	else
X                readsize = (int) lrec.compressed_size;
X	incnt = read(zipfd, inbuf, readsize);
X
X        lrec.compressed_size -= incnt;
X	inptr = inbuf;
X	return incnt--;
X}
X
X#ifndef	OLDC
Xint ReadByte(unsigned *x)
X#else
Xint ReadByte(x)
Xunsigned *x;
X#endif	/* OLDC */
X /* read a byte; return 8 if byte available, 0 if not */
X{
X	if (incnt-- == 0)
X		if (FillBuffer() == 0)
X			return 0;
X
X	*x = *inptr++;
X	return 8;
X}
X
X
X/* ------------------------------------------------------------- */
Xstatic unsigned mask_bits[] =
X        {0,     0x0001, 0x0003, 0x0007, 0x000f,
X                0x001f, 0x003f, 0x007f, 0x00ff,
X                0x01ff, 0x03ff, 0x07ff, 0x0fff,
X                0x1fff, 0x3fff, 0x7fff, 0xffff
X        };
X
X
X#ifndef	OLDC
Xint FillBitBuffer(register int bits)
X#else
Xint FillBitBuffer(bits)
Xregister int bits;
X#endif	/* OLDC */
X /* read a byte; return 8 if byte available, 0 if not */
X{
X	/* get the bits that are left and read the next word */
X	unsigned temp;
X        register int result = bitbuf;
X	int sbits = bits_left;
X	bits -= bits_left;
X
X	/* read next word of input */
X	bits_left = ReadByte(&bitbuf);
X	bits_left += ReadByte(&temp);
X	bitbuf |= (temp << 8);
X	if (bits_left == 0)
X		zipeof = 1;
X
X	/* get the remaining bits */
X        result = result | (int) ((bitbuf & mask_bits[bits]) << sbits);
X        bitbuf >>= bits;
X        bits_left -= bits;
X        return result;
X}
X
X#define READBIT(nbits,zdest,ztype) \
X	{ if (nbits <= bits_left) \
X		{ zdest = ztype(bitbuf & mask_bits[nbits]); \
X		bitbuf >>= nbits; bits_left -= nbits; } \
X	else zdest = ztype(FillBitBuffer(nbits));}
X
X/*
X * macro READBIT(nbits,zdest,ztype)
X *  {
X *      if (nbits <= bits_left) {
X *          zdest = ztype(bitbuf & mask_bits[nbits]);
X *          bitbuf >>= nbits;
X *          bits_left -= nbits;
X *      } else
X *          zdest = ztype(FillBitBuffer(nbits));
X *  }
X *
X */
X
X
X/* ------------------------------------------------------------- */
X
X#include "crc32.h"
X
X
X/* ------------------------------------------------------------- */
X
Xvoid FlushOutput(VOIDARG)
X /* flush contents of output buffer */
X{
X	UpdateCRC(outbuf, outcnt);
X	write(outfd, outbuf, outcnt);
X	outpos += outcnt;
X	outcnt = 0;
X	outptr = outbuf;
X}
X
X#define OUTB(intc) { *outptr++=intc; if (++outcnt==OUTBUFSIZ) FlushOutput(); }
X
X/*
X *  macro OUTB(intc)
X *  {
X *      *outptr++=intc;
X *      if (++outcnt==OUTBUFSIZ)
X *          FlushOutput();
X *  }
X *
X */
X
X
X/* ----------------------------------------------------------- */
X
Xvoid LoadFollowers(VOIDARG)
X{
X        register int x;
X        register int i;
X
X	for (x = 255; x >= 0; x--) {
X                READBIT(6,Slen[x],(byte));
X		for (i = 0; i < Slen[x]; i++) {
X                        READBIT(8,followers[x][i],(byte));
X		}
X	}
X}
X
X
X/* ----------------------------------------------------------- */
X/*
X * The Reducing algorithm is actually a combination of two
X * distinct algorithms.  The first algorithm compresses repeated
X * byte sequences, and the second algorithm takes the compressed
X * stream from the first algorithm and applies a probabilistic
X * compression method.
X */
X
Xint L_table[] = {0, 0x7f, 0x3f, 0x1f, 0x0f};
X
Xint D_shift[] = {0, 0x07, 0x06, 0x05, 0x04};
Xint D_mask[]  = {0, 0x01, 0x03, 0x07, 0x0f};
X
Xint B_table[] = {8, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5,
X		 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
X		 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
X		 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
X		 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
X		 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
X		 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
X		 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
X		 8, 8, 8, 8};
X
X/* ----------------------------------------------------------- */
X
Xvoid unReduce(VOIDARG)
X /* expand probablisticly reduced data */
X{
X        register int lchar;
X        int nchar;
X        int ExState;
X        int V;
X        int Len;
X
X        factor = lrec.compression_method - 1;
X	ExState = 0;
X	lchar = 0;
X	LoadFollowers();
X
X        while (((outpos+outcnt) < lrec.uncompressed_size) && (!zipeof)) {
X		if (Slen[lchar] == 0)
X                        READBIT(8,nchar,(int))      /* ; */
X                else
X		{
X                        READBIT(1,nchar,(int));
X                        if (nchar != 0)
X                                READBIT(8,nchar,(int))      /* ; */
X                        else
X			{
X                                int follower;
X                                int bitsneeded = B_table[Slen[lchar]];
X                                READBIT(bitsneeded,follower,(int));
X                                nchar = followers[lchar][follower];
X			}
X		}
X
X		/* expand the resulting byte */
X		switch (ExState) {
X
X		case 0:
X                        if (nchar != DLE)
X                                OUTB((byte) nchar) /*;*/
X			else
X				ExState = 1;
X			break;
X
X		case 1:
X                        if (nchar != 0) {
X                                V = nchar;
X				Len = V & L_table[factor];
X				if (Len == L_table[factor])
X					ExState = 2;
X				else
X					ExState = 3;
X			}
X			else {
X                                OUTB(DLE);
X				ExState = 0;
X			}
X			break;
X
X                case 2: {
X                                Len += nchar;
X				ExState = 3;
X			}
X			break;
X
X                case 3: {
X				register int i = Len + 3;
X				int offset = (((V >> D_shift[factor]) &
X                                          D_mask[factor]) << 8) + nchar + 1;
X                                longint op = (outpos+outcnt) - offset;
X
X				/* special case- before start of file */
X				while ((op < 0L) && (i > 0)) {
X					OUTB(0);
X					op++;
X					i--;
X				}
X
X				/* normal copy of data from output buffer */
X				{
X					register int ix = (int) (op % OUTBUFSIZ);
X
X                                        /* do a block memory copy if possible */
X                                        if ( ((ix    +i) < OUTBUFSIZ) &&
X                                             ((outcnt+i) < OUTBUFSIZ) ) {
X                                                memcpy(outptr,&outbuf[ix],i);
X                                                outptr += i;
X                                                outcnt += i;
X                                        }
X
X                                        /* otherwise copy byte by byte */
X                                        else while (i--) {
X                                                OUTB(outbuf[ix]);
X                                                if (++ix >= OUTBUFSIZ)
X                                                        ix = 0;
X                                        }
X                                }
X
X				ExState = 0;
X			}
X			break;
X		}
X
X                /* store character for next iteration */
X                lchar = nchar;
X        }
X}
X
X
X/* ------------------------------------------------------------- */
X/*
X * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
X * with partial clearing.
X *
X */
X
Xvoid partial_clear(VOIDARG)
X{
X        register int pr;
X        register int cd;
X
X	/* mark all nodes as potentially unused */
X	for (cd = first_ent; cd < free_ent; cd++)
X		prefix_of[cd] |= 0x8000;
X
X	/* unmark those that are used by other nodes */
X	for (cd = first_ent; cd < free_ent; cd++) {
X		pr = prefix_of[cd] & 0x7fff;	/* reference to another node? */
X                if (pr >= first_ent)            /* flag node as referenced */
X			prefix_of[pr] &= 0x7fff;
X	}
X
X	/* clear the ones that are still marked */
X	for (cd = first_ent; cd < free_ent; cd++)
X		if ((prefix_of[cd] & 0x8000) != 0)
X			prefix_of[cd] = -1;
X
X	/* find first cleared node as next free_ent */
X        cd = first_ent;
X        while ((cd < maxcodemax) && (prefix_of[cd] != -1))
X                cd++;
X        free_ent = cd;
X}
X
X
X/* ------------------------------------------------------------- */
X
Xvoid unShrink(VOIDARG)
X{
X#define  GetCode(dest) READBIT(codesize,dest,(int))
X
X	register int code;
X	register int stackp;
X	int finchar;
X	int oldcode;
X	int incode;
X
X
X	/* decompress the file */
X	maxcodemax = 1 << max_bits;
X	codesize = init_bits;
X	maxcode = (1 << codesize) - 1;
X	free_ent = first_ent;
X	offset = 0;
X	sizex = 0;
X
X	for (code = maxcodemax; code > 255; code--)
X		prefix_of[code] = -1;
X
X	for (code = 255; code >= 0; code--) {
X		prefix_of[code] = 0;
X		suffix_of[code] = (byte) code;
X	}
X
X	GetCode(oldcode);
X	if (zipeof)
X		return;
X	finchar = oldcode;
X
X        OUTB((byte) finchar);
X
X        stackp = hsize;
X
X	while (!zipeof) {
X		GetCode(code);
X		if (zipeof)
X			return;
X
X		while (code == clear) {
X			GetCode(code);
X			switch (code) {
X
X			case 1:{
X					codesize++;
X					if (codesize == max_bits)
X						maxcode = maxcodemax;
X					else
X						maxcode = (1 << codesize) - 1;
X				}
X				break;
X
X			case 2:
X				partial_clear();
X				break;
X			}
X
X			GetCode(code);
X			if (zipeof)
X				return;
X		}
X
X
X		/* special case for KwKwK string */
X		incode = code;
X		if (prefix_of[code] == -1) {
X                        stack[--stackp] = (byte) finchar;
X			code = oldcode;
X		}
X
X
X		/* generate output characters in reverse order */
X		while (code >= first_ent) {
X                        stack[--stackp] = suffix_of[code];
X			code = prefix_of[code];
X		}
X
X		finchar = suffix_of[code];
X                stack[--stackp] = (byte) finchar;
X
X
X                /* and put them out in forward order, block copy */
X                if ((hsize-stackp+outcnt) < OUTBUFSIZ) {
X                        memcpy(outptr,&stack[stackp],hsize-stackp);
X                        outptr += hsize-stackp;
X                        outcnt += hsize-stackp;
X                        stackp = hsize;
X                }
X
X                /* output byte by byte if we can't go by blocks */
X                else while (stackp < hsize)
X                        OUTB(stack[stackp++]);
X
X
X		/* generate new entry */
X		code = free_ent;
X		if (code < maxcodemax) {
X			prefix_of[code] = oldcode;
X			suffix_of[code] = (byte) finchar;
X
X			do
X				code++;
X			while ((code < maxcodemax) && (prefix_of[code] != -1));
X
X			free_ent = code;
X		}
X
X		/* remember previous code */
X		oldcode = incode;
X	}
X
X}
X
X
X/* ------------------------------------------------------------- */ 
X/*
X * Imploding
X * ---------
X *
X * The Imploding algorithm is actually a combination of two distinct
X * algorithms.  The first algorithm compresses repeated byte sequences
X * using a sliding dictionary.  The second algorithm is used to compress
X * the encoding of the sliding dictionary ouput, using multiple
X * Shannon-Fano trees.
X *
X */ 
X
X#define maxSF 256
X
X   typedef struct sf_entry { 
X                 word         Code; 
X                 byte         Value; 
X                 byte         BitLength; 
X              } sf_entry; 
X
X   typedef struct sf_tree {   /* a shannon-fano tree */ 
X      sf_entry     entry[maxSF];
X      int          entries;
X      int          MaxLength;
X   } sf_tree; 
X
X   typedef sf_tree      *sf_treep; 
X
X   sf_tree      lit_tree; 
X   sf_tree      length_tree; 
X   sf_tree      distance_tree; 
X   boolean      lit_tree_present; 
X   boolean      eightK_dictionary; 
X   int          minimum_match_length;
X   int          dict_bits;
X
X
X#ifndef	OLDC
Xvoid SortLengths(sf_tree *tree)
X#else
Xvoid SortLengths(tree)
Xsf_tree *tree;
X#endif	/* OLDC */
X  /* Sort the Bit Lengths in ascending order, while retaining the order
X    of the original lengths stored in the file */ 
X{ 
X   int          x;
X   int          gap;
X   sf_entry     t; 
X   boolean      noswaps;
X   int          a, b;
X
X   gap = tree->entries / 2; 
X
X   do { 
X      do { 
X         noswaps = 1;
X         for (x = 0; x <= (tree->entries - 1) - gap; x++) 
X         { 
X            a = tree->entry[x].BitLength; 
X            b = tree->entry[x + gap].BitLength; 
X            if ((a > b) || ((a == b) && (tree->entry[x].Value > tree->entry[x + gap].Value))) 
X            { 
X               t = tree->entry[x]; 
X               tree->entry[x] = tree->entry[x + gap]; 
X               tree->entry[x + gap] = t; 
X               noswaps = 0;
X            } 
X         } 
X      }  while (!noswaps);
X
X      gap = gap / 2; 
X   }  while (gap > 0);
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid ReadLengths(sf_tree *tree)
X#else
Xvoid ReadLengths(tree)
Xsf_tree *tree;
X#endif	/* OLDC */
X{ 
X   int          treeBytes;
X   int          i;
X   int          num, len;
X
X  /* get number of bytes in compressed tree */
X   READBIT(8,treeBytes,(int));
X   treeBytes++; 
X   i = 0; 
X
X   tree->MaxLength = 0;
X
X /* High 4 bits: Number of values at this bit length + 1. (1 - 16)
X    Low  4 bits: Bit Length needed to represent value + 1. (1 - 16) */
X   while (treeBytes > 0)
X   {
X      READBIT(4,len,(int)); len++;
X      READBIT(4,num,(int)); num++;
X
X      while (num > 0)
X      {
X         if (len > tree->MaxLength)
X            tree->MaxLength = len;
X         tree->entry[i].BitLength = (byte) len;
X         tree->entry[i].Value = (byte) i;
X         i++;
X         num--;
X      }
X
X      treeBytes--;
X   } 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid GenerateTrees(sf_tree *tree)
X#else
Xvoid GenerateTrees(tree)
Xsf_tree *tree;
X#endif	/* OLDC */
X     /* Generate the Shannon-Fano trees */ 
X{ 
X   word         Code;
X   int          CodeIncrement;
X   int          LastBitLength;
X   int          i;
X
X
X   Code = 0;
X   CodeIncrement = 0; 
X   LastBitLength = 0; 
X
X   i = tree->entries - 1;   /* either 255 or 63 */ 
X   while (i >= 0) 
X   { 
X      Code += CodeIncrement; 
X      if (tree->entry[i].BitLength != (byte) LastBitLength) 
X      { 
X         LastBitLength = tree->entry[i].BitLength; 
X         CodeIncrement = 1 << (16 - LastBitLength); 
X      } 
X
X      tree->entry[i].Code = Code; 
X      i--; 
X   } 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid ReverseBits(sf_tree *tree)
X#else
Xvoid ReverseBits(tree)
Xsf_tree *tree;
X#endif	/* OLDC */
X /* Reverse the order of all the bits in the above ShannonCode[]
X    vector, so that the most significant bit becomes the least
X    significant bit. For example, the value 0x1234 (hex) would become
X    0x2C48 (hex). */ 
X{ 
X   int          i;
X   word         mask;
X   word         revb;
X   word         v;
X   word         o;
X   int          b;
X
X
X   for (i = 0; i <= tree->entries - 1; i++) 
X   { 
X        /* get original code */ 
X      o = tree->entry[i].Code; 
X
X        /* reverse each bit */ 
X      mask = 0x0001;
X      revb = 0x8000;
X      v = 0;
X      for (b = 0; b <= 15; b++) 
X      { 
X           /* if bit set in mask, then substitute reversed bit */ 
X         if ((o & mask) != 0) 
X            v = v | revb; 
X
X           /* advance to next bit */ 
X         revb = (revb >> 1);
X         mask = (mask << 1);
X      } 
X
X        /* store reversed bits */ 
X      tree->entry[i].Code = v; 
X   } 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid LoadTree(sf_tree *tree, int treesize)
X#else
Xvoid LoadTree(tree, treesize)
Xsf_tree *tree;
Xint treesize;
X#endif	/* OLDC */
X     /* allocate and load a shannon-fano tree from the compressed file */ 
X{ 
X   tree->entries = treesize; 
X   ReadLengths(tree); 
X   SortLengths(tree); 
X   GenerateTrees(tree); 
X   ReverseBits(tree); 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid LoadTrees(void)
X#else
Xvoid LoadTrees()
X#endif	/* OLDC */
X{ 
X   /* bit 1... */
X   eightK_dictionary = (boolean) ((lrec.general_purpose_bit_flag & 0x02) != 0);
X   /* bit 2... */
X   lit_tree_present = (boolean) ((lrec.general_purpose_bit_flag & 0x04) != 0);
X
X   if (eightK_dictionary) 
X      dict_bits = 7;
X   else 
X      dict_bits = 6; 
X
X   if (lit_tree_present) 
X   { 
X      minimum_match_length = 3; 
X      LoadTree(&lit_tree,256); 
X   } 
X   else 
X      minimum_match_length = 2; 
X
X   LoadTree(&length_tree,64); 
X   LoadTree(&distance_tree,64); 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid ReadTree(sf_tree *tree, int *dest)
X#else
Xvoid ReadTree(tree, dest)
Xsf_tree *tree;
Xint *dest;
X#endif	/* OLDC */
X     /* read next byte using a shannon-fano tree */ 
X{ 
X   int          bits = 0;
X   word         cv = 0;
X   int          cur = 0;
X   int          b;
X
X   *dest = -1;   /* in case of error */ 
X
X   for (;;)
X   { 
X      READBIT(1,b,(int));
X      cv = cv | (b << bits);
X      bits++; 
X
X      /* this is a very poor way of decoding shannon-fano.  two quicker
X         methods come to mind:
X            a) arrange the tree as a huffman-style binary tree with
X               a "leaf" indicator at each node,
X         and
X            b) take advantage of the fact that s-f codes are at most 8
X               bits long and alias unused codes for all bits following
X               the "leaf" bit.
X      */
X
X      while (tree->entry[cur].BitLength < (byte) bits) 
X      { 
X         cur++; 
X         if (cur >= tree->entries) 
X            return; /* data error */
X      } 
X
X      while (tree->entry[cur].BitLength == (byte) bits) 
X      { 
X         if (tree->entry[cur].Code == cv) 
X         { 
X            *dest = tree->entry[cur].Value; 
X            return; 
X         } 
X
X         cur++; 
X         if (cur >= tree->entries) 
X            return; /* data error */
X      } 
X   } 
X} 
X
X
X/* ----------------------------------------------------------- */ 
X
X#ifndef	OLDC
Xvoid unImplode(void)
X#else
Xvoid unImplode()
X#endif	/* OLDC */
X     /* expand imploded data */ 
X
X{ 
X   int          lout;
X   longint      op;
X   int          Length;
X   int          Distance;
X
X   LoadTrees(); 
X
X   while ((!zipeof) && ((outpos+outcnt) < lrec.uncompressed_size))
X   { 
X      READBIT(1,lout,(int));
X
X      if (lout != 0)   /* encoded data is literal data */ 
X      { 
X         if (lit_tree_present)  /* use Literal Shannon-Fano tree */
X            ReadTree(&lit_tree,&lout);
X         else 
X            READBIT(8,lout,(int));
X
X         OUTB((byte) lout);
X      } 
X      else             /* encoded data is sliding dictionary match */
X      {                
X         READBIT(dict_bits,lout,(int));
X         Distance = lout; 
X
X         ReadTree(&distance_tree,&lout); 
X         Distance |= (lout << dict_bits);
X         /* using the Distance Shannon-Fano tree, read and decode the
X            upper 6 bits of the Distance value */ 
X
X         ReadTree(&length_tree,&Length); 
X         /* using the Length Shannon-Fano tree, read and decode the
X            Length value */
X
X         Length += minimum_match_length; 
X         if (Length == (63 + minimum_match_length)) 
X         { 
X            READBIT(8,lout,(int));
X            Length += lout; 
X         } 
X
X        /* move backwards Distance+1 bytes in the output stream, and copy
X          Length characters from this position to the output stream.
X          (if this position is before the start of the output stream,
X          then assume that all the data before the start of the output
X          stream is filled with zeros) */ 
X
X         op = (outpos+outcnt) - Distance - 1L;
X
X          /* special case- before start of file */
X          while ((op < 0L) && (Length > 0)) {
X                  OUTB(0);
X                  op++;
X                  Length--;
X          }
X
X          /* normal copy of data from output buffer */
X          {
X                  register int ix = (int) (op % OUTBUFSIZ);
X
X                  /* do a block memory copy if possible */
X                  if ( ((ix    +Length) < OUTBUFSIZ) &&
X                       ((outcnt+Length) < OUTBUFSIZ) ) {
X                          memcpy(outptr,&outbuf[ix],Length);
X                          outptr += Length;
X                          outcnt += Length;
X                  }
X
X                  /* otherwise copy byte by byte */
X                  else while (Length--) {
X                          OUTB(outbuf[ix]);
X                          if (++ix >= OUTBUFSIZ)
X                                  ix = 0;
X                  }
X         }
X      } 
X   } 
X} 
X
X
X
X/* ---------------------------------------------------------- */
X
Xvoid extract_member(VOIDARG)
X{
X        unsigned b;
X
X	bits_left = 0;
X	bitbuf = 0;
X	incnt = 0;
X	outpos = 0L;
X	outcnt = 0;
X	outptr = outbuf;
X	zipeof = 0;
X	crc32val = 0xFFFFFFFFL;
X
X
X	/* create the output file with READ and WRITE permissions */
X	if (create_output_file())
X		exit(1);
X
X        switch (lrec.compression_method) {
X
X	case 0:		/* stored */
X		{
X			printf(" Extracting: %-12s ", filename);
X			while (ReadByte(&b))
X				OUTB((byte) b);
X		}
X		break;
X
X        case 1: {
X			printf("UnShrinking: %-12s ", filename);
X			unShrink();
X		}
X		break;
X
X	case 2:
X	case 3:
X	case 4:
X        case 5: {
X			printf("  Expanding: %-12s ", filename);
X			unReduce();
X		}
X		break;
X
X        case 6: {
X                        printf("  Exploding: %-12s ", filename);
X                        unImplode();
X		}
X		break;
X
X        default:
X		printf("Unknown compression method.");
X	}
X
X
X	/* write the last partial buffer, if any */
X	if (outcnt > 0) {
X		UpdateCRC(outbuf, outcnt);
X		write(outfd, outbuf, outcnt);
X	}
X
X	/* set output file date and time */
X	set_file_time();
X
X	close(outfd);
X
X	crc32val = -1 - crc32val;
X        if (crc32val != lrec.crc32)
X                printf(" Bad CRC %08lx  (should be %08lx)", lrec.crc32, crc32val);
X
X	printf("\n");
X}
X
X
X/* ---------------------------------------------------------- */
X
X#ifndef	OLDC
Xvoid get_string(int len, char *s)
X#else
Xvoid get_string(len, s)
Xint len;
Xchar *s;
X#endif	/* OLDC */
X /* read a byte; return 8 if byte available, 0 if not */
X{
X	read(zipfd, s, len);
X	s[len] = 0;
X}
X
X
X/* ---------------------------------------------------------- */
X
Xvoid process_local_file_header(VOIDARG)
X{
X	if ((long) &lrec.crc32 ==
X			(long) &lrec.last_mod_file_date
X			+ sizeof(lrec.last_mod_file_date))
X		read(zipfd, (char *) &lrec, sizeof(lrec));
X	else {
X		read(zipfd, (char *) &lrec, (unsigned)
X			((long) &lrec.last_mod_file_date
X			+ sizeof(lrec.last_mod_file_date)
X			- (long) &lrec));
X		read(zipfd, (char *) &lrec.crc32, (unsigned)
X			((long) &lrec.extra_field_length
X			+ sizeof(lrec.extra_field_length)
X			- (long) &lrec.crc32));
X	}
X
X#ifdef HIGH_LOW
X	swap_bytes(&lrec.version_needed_to_extract);
X	swap_bytes(&lrec.general_purpose_bit_flag);
X	swap_bytes(&lrec.compression_method);
X	swap_bytes(&lrec.last_mod_file_time);
X	swap_bytes(&lrec.last_mod_file_date);
X	swap_lbytes(&lrec.crc32);
X	swap_lbytes(&lrec.compressed_size);
X	swap_lbytes(&lrec.uncompressed_size);
X	swap_bytes(&lrec.filename_length);
X	swap_bytes(&lrec.extra_field_length);
X#endif	/* HIGH_LOW */
X
X	get_string(lrec.filename_length, filename);
X	get_string(lrec.extra_field_length, extra);
X#ifdef	unix
X	{
X		char *cp;
X		for (cp = filename; *cp; ++cp)
X			if (isupper(*cp)) *cp = tolower(*cp);
X	}
X#endif	/* unix */
X	extract_member();
X}
X
X
X/* ---------------------------------------------------------- */
X
Xvoid process_central_file_header(VOIDARG)
X{
X	central_directory_file_header rec;
X	char filename[STRSIZ];
X	char extra[STRSIZ];
X	char comment[STRSIZ];
X
X	if ((long) &rec.external_file_attributes ==
X			(long) &rec.internal_file_attributes
X			+ sizeof(rec.internal_file_attributes))
X		read(zipfd, (char *) &rec, sizeof(rec));
X	else {
X		read(zipfd, (char *) &rec, (unsigned)
X			((long) &rec.internal_file_attributes
X			+ sizeof(rec.internal_file_attributes)
X			- (long) &rec));
X		read(zipfd, (char *) &rec.external_file_attributes, (unsigned)
X			((long) &rec.relative_offset_local_header
X			+ sizeof(rec.relative_offset_local_header)
X			- (long) &rec.external_file_attributes));
X	}
X
X#ifdef HIGH_LOW
X	swap_bytes(&rec.version_made_by);
X	swap_bytes(&rec.version_needed_to_extract);
X	swap_bytes(&rec.general_purpose_bit_flag);
X	swap_bytes(&rec.compression_method);
X	swap_bytes(&rec.last_mod_file_time);
X	swap_bytes(&rec.last_mod_file_date);
X	swap_lbytes(&rec.crc32);
X	swap_lbytes(&rec.compressed_size);
X	swap_lbytes(&rec.uncompressed_size);
X	swap_bytes(&rec.filename_length);
X	swap_bytes(&rec.extra_field_length);
X	swap_bytes(&rec.file_comment_length);
X	swap_bytes(&rec.disk_number_start);
X	swap_bytes(&rec.internal_file_attributes);
X	swap_lbytes(&rec.external_file_attributes);
X	swap_lbytes(&rec.relative_offset_local_header);
X#endif	/* HIGH_LOW */
X
X        get_string(rec.filename_length, filename);
X	get_string(rec.extra_field_length, extra);
X	get_string(rec.file_comment_length, comment);
X#ifdef	unix
X	{
X		char *cp;
X		for (cp = filename; *cp; ++cp)
X			if (isupper(*cp)) *cp = tolower(*cp);
X	}
X#endif	/* unix */
X}
X
X
X/* ---------------------------------------------------------- */
X
Xvoid process_end_central_dir(VOIDARG)
X{
X	end_central_dir_record rec;
X	char comment[STRSIZ];
X
X	read(zipfd, (char *) &rec, sizeof(rec));
X
X#ifdef HIGH_LOW
X	swap_bytes(&rec.number_this_disk);
X#ifndef	TURBOC
X	swap_bytes(&rec.num_disk_with_start_cent_dir);
X	swap_bytes(&rec.tot_ents_cent_dir_on_this_disk);
X#else
X	swap_bytes(&rec.number_disk_with_start_central_directory);
X	swap_bytes(&rec.total_entries_central_dir_on_this_disk);
X#endif	/* TURBOC */
X	swap_bytes(&rec.total_entries_central_dir);
X	swap_lbytes(&rec.size_central_directory);
X	swap_lbytes(&rec.offset_start_central_directory);
X	swap_bytes(&rec.zipfile_comment_length);
X#endif	/* HIGH_LOW */
X
X	get_string(rec.zipfile_comment_length, comment);
X}
X
X
X/* ---------------------------------------------------------- */
X
Xvoid process_headers(VOIDARG)
X{
X	longint sig;
X
X	while (1) {
X		if (read(zipfd, (char *) &sig, sizeof(sig)) != sizeof(sig))
X			return;
X
X#ifdef HIGH_LOW
X		swap_lbytes(&sig);
X#endif	/* HIGH_LOW */
X
X                if (sig == LOCAL_FILE_HEADER_SIGNATURE)
X			process_local_file_header();
X                else if (sig == CENTRAL_FILE_HEADER_SIGNATURE)
X			process_central_file_header();
X                else if (sig == END_CENTRAL_DIR_SIGNATURE) {
X			process_end_central_dir();
X			return;
X		}
X                else {
X			printf("Invalid Zipfile Header (0x%.8lx)\n", sig);
X			return;
X		}
X	}
X
X}
X
X
X/* ---------------------------------------------------------- */
X
Xvoid extract_zipfile(VOIDARG)
X{
X	/*
X	 * open the zipfile for reading and in BINARY mode to prevent cr/lf
X	 * translation, which would corrupt the bitstreams 
X	 */
X
X	if (open_input_file())
X		exit(1);
X
X#ifdef HIGH_LOW
X	{
X		word w_sig;
X		longint li_sig;
X		char *bp, *bp0 = (char *)&li_sig, *bp3 = ((char *)&li_sig)+3;
X
X		if (read(zipfd, (char *) &w_sig, 2) == 2)
X			if (w_sig == (LOCAL_FILE_HEADER_SIGNATURE & 0xffff)) {
X				w0 = 0;
X				w1 = 1;
X			} else {
X				w0 = 1;
X				w1 = 0;
X			}
X		lseek(zipfd, 0L, SEEK_SET);
X		if (read(zipfd, (char *) &li_sig, 4) == 4)
X			if (li_sig == LOCAL_FILE_HEADER_SIGNATURE) {
X				li0 = 0;
X				li1 = 1;
X				li2 = 2;
X				li3 = 3;
X			} else {
X				li0 = li1 = li2 = li3 = 0;
X				for (bp = bp0; bp < bp3; ++bp, ++li0)
X					if (*bp < 0x4b && !(*bp & 0x01))
X						break;
X				for (bp = bp0; bp < bp3; ++bp, ++li1)
X					if (*bp < 0x4b && (*bp & 0x01))
X						break;
X				for (bp = bp0; bp < bp3; ++bp, ++li2)
X					if (*bp == ((LOCAL_FILE_HEADER_SIGNATURE
X							>> 8) & 0xffL))
X						break;
X				for (bp = bp0; bp < bp3; ++bp, ++li3)
X					if (*bp == (LOCAL_FILE_HEADER_SIGNATURE
X							& 0xffL))
X						break;
X			}
X		lseek(zipfd, 0L, SEEK_SET);
X	}
X#endif	/* HIGH_LOW */
X
X	process_headers();
X
X	close(zipfd);
X}
X
X
X/* ---------------------------------------------------------- */
X/*
X * main program
X *
X */
X
X#ifndef	OLDC
Xvoid main(int argc, char **argv)
X#else
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X#endif	/* OLDC */
X /* read a byte; return 8 if byte available, 0 if not */
X{
X	if (argc != 2) {
X                printf("\n%s\nCourtesy of:  S.H.Smith  and  The Tool Shop BBS,  (602) 279-2673.\n\n",VERSION);
X		printf("You may copy and distribute this program freely, provided that:\n");
X		printf("    1)   No fee is charged for such copying and distribution, and\n");
X		printf("    2)   It is distributed ONLY in its original, unmodified state.\n\n");
X		printf("If you wish to distribute a modified version of this program, you MUST\n");
X		printf("include the source code.\n\n");
X		printf("If you modify this program, I would appreciate a copy of the  new source\n");
X		printf("code.   I am holding the copyright on the source code, so please don't\n");
X		printf("delete my name from the program files or from the documentation.\n\n");
X                printf("IN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST\n");
X                printf("PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES\n");
X                printf("ARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY\n");
X                printf("CLAIM BY ANY OTHER PARTY.\n\n");
X                printf("Usage:  UnZip FILE[.zip]\n");
X                exit(1);
X	}
X
X	/* .ZIP default if none provided by user */
X	strcpy(zipfn, argv[1]);
X	if (strchr(zipfn, '.') == NULL)
X		strcat(zipfn, ".zip");
X
X        /* allocate i/o buffers */
X	inbuf = (byte *) (malloc(INBUFSIZ));
X	outbuf = (byte *) (malloc(OUTBUFSIZ));
X	if ((inbuf == NULL) || (outbuf == NULL)) {
X		printf("Can't allocate buffers!\n");
X		exit(1);
X	}
X
X        /* do the job... */
X        extract_zipfile();
X	exit(0);
X}
X
SHAR_EOF
fi
if test -f 'unzip.doc'
then
	echo shar: "will not over-write existing file 'unzip.doc'"
else
sed 's/^X//' << \SHAR_EOF > 'unzip.doc'
X  
X                                   UnZip
X  
X                           Version 2.0.1, 09-16-89
X  
X                           Zipfile Extract Utility
X  
X          Copyright (C) 1989 Samuel H. Smith;  ALL RIGHTS RESERVED
X  
X  
X'UnZip' is a small Zipfile extract utility.   It is written to be as
Xsmall and portable as possible -- ideal as a starting point for handling
X.ZIP files in non-IBM environments.
X
XSource code is provided in C and Turbo Pascal.  If you port this program
Xto a non-IBM system, I would appreciate a copy of the ported source and
Xexec files.
X
X
XUsage
X-----
X   unz filename[.zip]           ;pascal language version
X   unzip filename[.zip]         ;C language version
X
X
XRevision history
X----------------
X
X3-3-89
X   Initial alpha test release.
X
X3-5-89
X   First fully operational release.  Does not implement CRC verification,
X   but should correctly unzip all compression methods.
X
X3-6-89
X   Corrected end-of-file detection in both shrink and reduce expanders.
X   Resulting files should now always have the correct size.  Added ".ZIP"
X   default to unzip.c to match calling conventions of unz.pas.
X
X3-8-89
X   Moved machine and operating-system specific code to a block starting
X   around line 180.  Added code to swap bytes on host machines that
X   store the high order bytes in lower address locations than the low
X   order bytes.
X
X3-15-89
X   Added CRC checking in UNZIP.C.  Speeded operation by about 150%.
X
X   I'm spending my time on the C version now and don't plan to do any
X   further work on the pascal.  If you're using the pascal version
X   please contact me.
X
X9-9-89
X   Addition of new "un-implode" logic to handle new compression format
X   included with PKZ101.
X
X9-16-89
X   Portable version created by George M. Sipe (rebel!george).  Should
X   now more easily be ported to other systems and compilers.
X
X
X
XLICENSE
X=======
X
XYou may copy and distribute this program freely, provided that:
X    1)   No fee is charged for such copying and distribution, and
X    2)   It is distributed ONLY in its original, unmodified state.
X
XIf you wish to distribute a modified version of this program, you MUST
Xinclude the source code.
X
XIf you modify this program, I would appreciate a copy of the new source
Xcode.  I am holding the copyright on the source code, so please don't
Xdelete my name from the program files or from the documentation.
X
X
XSUPPORT
X=======
X
XI work very hard to produce a software package of the highest quality
Xand functionality.  I try to look into all reported bugs, and will
Xgenerally fix reported problems within a few days.
X
XIN NO EVENT WILL I BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST
XPROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES
XARISING OUT OF YOUR USE OR INABILITY TO USE THE PROGRAM, OR FOR ANY
XCLAIM BY ANY OTHER PARTY.
X
XIf you have any questions, bugs, or suggestions, please contact me at:
X
X                  The Tool Shop BBS
X                  (602) 279-2673 (FREE LINE, USR 2400)
X                  (602) 264-3969 (HST 9600)
X                  (602) 270-0239 (HAYES 9600)
X
XThe latest version is always available for downloading.  (Except
Xpossibly this portable version.)
X
XEnjoy!     Samuel H. Smith
X           Author and Sysop of The Tool Shop.
X   
SHAR_EOF
fi
exit 0
#	End of shell archive

-- 
George M. Sipe,		       Phone: (404) 447-4731
537 Lakeshore Drive, Berkeley Lake, GA  30136-3035
UUCP: ...!{decvax,linus,rutgers}!gatech!rebel!george