[alt.sources] fixed unzip

sandy@conexch.UUCP (Sandford Zelkovitz) (04/08/89)

The following code is the fixed version of unzip, written by S.H. Smith. It
now compiles problem under Xenix386 and also fixes the bug in subroutine
get_string. I hope the author does not mind that I have reposted his
program. ............ Sandy

---------------cut/ax/hack/snip/chop/whatever here -----------------------
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  addbfcrc.c
#	  unzipbsd.c
#
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile for unzipbsd
X
X
X# "make unzip"    -- makes unzip in current directory
X# "make install"  -- makes unzip, then moves it into DESTDIR defined below
X# "make clean"    -- deletes object files and executable unzip from current dir
X# "make shar"     -- make a SHell ARchive
X
X# Directory where we want to move executable unzip on "make install"
XDESTDIR=/usr/public
X
X# CFLAGS are flags for the C compiler.  LDFLAGS are flags for the loader.
XCFLAGS= -O 
XLDFLAGS= -s
X
XCC=cc
X
X.c.o :
X	$(CC) -c $(CFLAGS) $*.c
X
XOBJS = unzipbsd.o addbfcrc.o
X
Xunzip: $(OBJS)
X	cc $(LDFLAGS) -o unzip $(OBJS)
X
Xunzip.o: unzip.c
X
Xaddbfcrc.o: addbfcrc.c
X
Xinstall: unzip
X	mv unzip $(DESTDIR)/unzip
X
Xclean:
X	/bin/rm -f $(OBJS) core unzip
X
Xshar:
X	@shar -a Makefile unzipbsd.c addbfcrc.c > unzipbsd.shar
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > addbfcrc.c &&
X/* @(#) addbfcrc.c 1.5 89/03/08 14:58:35 */
X/* Most of following CRC-32 stuff is from zmodem source code */
X
X#ifndef LINT
Xstatic char sccsid[]="::[[ @(#) addbfcrc.c 1.6 89/03/10 19:08:47 ]]::";
X#endif
X
X/* I claim no copyright over the contents of this file.  -- Rahul Dhesi */
X
X/*
XChecksum:  951252172      (check or update this with "brik")
X*/
X
X
Xlong crccode;
X
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
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/* 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
Xlong crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
X      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
X      0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
X      0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
X      0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X      0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
X      0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X      0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
X      0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
X      0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
X      0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
X      0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
X      0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X      0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
X      0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X      0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
X      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
X      0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
X      0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X      0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
X      0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
X      0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
X      0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
X      0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
X      0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X      0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
X      0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
X      0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
X      0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
X      0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
X      0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
X      0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
X      0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
X      0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X      0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
X      0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X      0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
X      0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
X      0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
X      0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
X      0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
X      0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X      0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
X      0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X      0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
X      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
X      0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
X      0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X      0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
X      0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
X      0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
X      0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
X      0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
X      0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X      0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
X      0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
X      0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
X      0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
X      0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
X      0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
X      0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
X      0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
X      0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
Xaddbfcrc (buf, size)
Xregister char *buf;
Xregister int size;
X{
X   int i;
X   for (i = 0;  i < size;  i ++) {
X      crccode = crc_32_tab[(int) ((crccode) ^ (buf[i])) & 0xff] ^
X         (((crccode) >> 8) & 0x00FFFFFFL);
X   }
X}
SHAR_EOF
chmod 0644 addbfcrc.c || echo "restore of addbfcrc.c fails"
sed 's/^X//' << 'SHAR_EOF' > unzipbsd.c &&
X/*
X * Quick hack to use on BSD, on a DEC VAX
X * By Michael Enkelis @ tektronix 04/03/89
X *
X */
X
X/*
X * Copyright 1987, 1989 Samuel H. Smith;  All rights reserved
X *
X * This is a component of the ProDoor System.
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 */ 
X
X#define version  "UnZip:  Zipfile Extract v1.1b of 04-03-89; (C) 1989 S.H.Smith"
X
Xtypedef unsigned char byte;
Xtypedef unsigned int word;
Xtypedef unsigned long longint;
Xtypedef unsigned char boolean;
X#define STRSIZ  256
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X
X
Xint errcount = 0;		/* count of errors */
Xint debugging = 0;		/* debug enable flag */
Xint verbose = 0;		/* be verbose */
Xint test_zip = 0;		/* test CRC's only */
X
X#ifdef M_XENIX
Xint L_SET = 1;
X#endif
X
X/*
XInitializing the CRC to all one bits avoids failure of detection
Xshould entire data stream get cyclically bit-shifted by one position.
XThe calculation of the probability of this happening is left as
Xan exercise for the reader.
X*/
X#define INITCRC	0xFFFFFFFFL;
Xextern long crccode;
X
X/* ----------------------------------------------------------- */ 
X/*
X * Zipfile layout declarations
X *
X */ 
X
Xtypedef longint	signature_type;
X
X
X#define local_file_header_signature  0x04034b50L
X
Xchar *strchr();
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#define central_file_header_signature  0x02014b50L
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#define end_central_dir_signature  0x06054b50L
X
Xtypedef struct end_central_dir_record { 
X	word	  number_this_disk; 
X	word	  number_disk_with_start_central_directory; 
X	word	  total_entries_central_dir_on_this_disk; 
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 * input file variables
X *
X */ 
X
X
X#define  uinbufsize	512L	/* input buffer size */
X	byte	inbuf[uinbufsize];
X
X	boolean  zipeof;
X	longint  csize;
X	longint  cusize;
X	int	cmethod;
X	int	inpos;
X	int	incnt;
X	int	pc;
X	int	pcbits;
X	int	pcbitv;
X	
X	int	zipfd;
X	char	zipfn[STRSIZ];
X	local_file_header lrec;
X
X
X
X
X/* ----------------------------------------------------------- */ 
X/*
X * output stream variables
X *
X */ 
X
X
X	byte	outbuf[4096];	/* for rle look-back */
X	longint  outpos;	  /* absolute position in outfile */
X	int	outcnt;
X
X	int	outfd;
X	char	filename[STRSIZ];
X	char	extra[STRSIZ];
X
X
X
X/* ----------------------------------------------------------- */ 
X/*
X * shrink/reduce working storage
X *
X */ 
X
X
X	int	factor;
X	byte	followers[256][64];
X	byte	Slen[256];
X	int	ExState;
X	int	C;
X	int	V;
X	int	Len;
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
X	typedef int  hsize_array_integer[hsize+1];
X	typedef byte hsize_array_byte[hsize+1];
X
X	hsize_array_integer prefix_of;
X	hsize_array_byte	suffix_of;
X	hsize_array_byte	stack;
X
X	int	cbits;
X	int	maxcode;
X	int	free_ent;
X	int	maxcodemax;
X	int	offset;
X	int	sizex;
X
X
X/* ------------------------------------------------------------- */ 
X
Xskip_csize()
X{ 
X	lseek(zipfd,csize,L_SET);
X	zipeof = 1;
X	csize = 0L; 
X	incnt = 0; 
X} 
X
X
X/* ------------------------------------------------------------- */ 
X
XReadByte(x)
Xint *x;
X{ 
X	if (incnt == 0) 
X	{ 
X	if (csize == 0L) 
X	{ 
X	  zipeof = 1;
X	  return;
X	} 
X
X	inpos = sizeof(inbuf);
X	if (inpos > csize) 
X	  inpos = (int)csize;
X	incnt = read(zipfd,inbuf,inpos);
X
X	inpos = 1; 
X	csize -= incnt; 
X	} 
X
X	*x = inbuf[inpos-1]; 
X	inpos++; 
X	incnt--; 
X} 
X
X
X/* ------------------------------------------------------------- */ 
X
XReadBits(bits,x)
Xint bits,*x;
X	/* read the specified number of bits */ 
X{ 
X	int	bit;
X	int	bitv;
X
X	*x = 0;
X	bitv = 1;
X
X	for (bit = 0; bit <= bits-1; bit++)
X	{ 
X
X	if (pcbits > 0) 
X	{ 
X	  pcbits--; 
X	  pcbitv = pcbitv << 1; 
X	} 
X	else 
X
X	{ 
X	  ReadByte(&pc); 
X	  pcbits = 7; 
X	  pcbitv = 1; 
X	} 
X
X	if ((pc & pcbitv) != 0) 
X	  *x = *x | bitv; 
X
X	bitv = (int) (bitv << 1);
X	} 
X
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xget_string(len, s)
Xint len;
Xchar *s;
X{ 
X	read(zipfd,s,len);
X	s[len] = 0;
X} 
X
X
X/* ------------------------------------------------------------- */ 
X
XOutByte(c)
Xint c;
X	/* output each character from archive to screen */ 
X{ 
X	outbuf[outcnt /* outpos % sizeof(outbuf) */] = c;
X	outpos++; 
X	outcnt++;
X 
X	if (outcnt == sizeof(outbuf)) 
X	{ 
X	if (test_zip == 0)
X		write(outfd,outbuf,outcnt);
X	addbfcrc (outbuf, outcnt);
X	outcnt = 0; 
X	printf("."); 
X	} 
X} 
X
X
X/* ----------------------------------------------------------- */
X	
Xreduce_L(x)
Xint x;
X	{ 
X	switch (factor) {
X	  case 1:	return x & 0x7f; 
X	  case 2:	return x & 0x3f; 
X	  case 3:	return x & 0x1f; 
X	  case 4:	return x & 0x0f; 
X	} 
X	return 0; /* error */
X	} 
X
X	
Xreduce_F(x)
Xint x;
X	{ 
X	switch (factor) {
X	  case 1:	if (x == 127) return 2;  else return 3;
X	  case 2:	if (x == 63) return 2;	else return 3;
X	  case 3:	if (x == 31) return 2;	else return 3;
X	  case 4:	if (x == 15) return 2;	else return 3;
X	} 
X	return 0; /* error */
X	} 
X
X	
Xreduce_D(x,y)
Xint x,y;
X	{ 
X	switch (factor) {
X	  case 1:	return ((x >> 7) & 0x01) * 256 + y + 1; 
X	  case 2:	return ((x >> 6) & 0x03) * 256 + y + 1; 
X	  case 3:	return ((x >> 5) & 0x07) * 256 + y + 1; 
X	  case 4:	return ((x >> 4) & 0x0f) * 256 + y + 1; 
X	} 
X	return 0; /* error */
X	} 
X
X
Xreduce_B(x)
Xint x;
X	 /* number of bits needed to encode the specified number */ 
X	{ 
X	switch (x - 1) {
X	  
X	  case 0:	
X	  case 1:	return 1; 
X	  
X	  case 2:	
X	  case 3:	return 2; 
X	  
X	  case 4:
X	  case 5:	
X	  case 6:	
X	  case 7:	return 3; 
X	  
X	  case 8:	
X	  case 9:	
X	  case 10:	
X	  case 11:	
X	  case 12:	
X	  case 13:	
X	  case 14:	
X	  case 15:	return 4; 
X	 
X	  case 16:
X	  case 17:
X	  case 18:
X	  case 19:
X	  case 20:
X	  case 21:
X	  case 22:
X	  case 23:
X	  case 24:
X	  case 25:
X	  case 26:
X	  case 27:
X	  case 28:
X	  case 29:
X	  case 30:
X	  case 31:	return 5;
X	 
X	  case 32:
X	  case 33:
X	  case 34:
X	  case 35:
X	  case 36:
X	  case 37:
X	  case 38:
X	  case 39:
X	  case 40:
X	  case 41:
X	  case 42:
X	  case 43:
X	  case 44:
X	  case 45:
X	  case 46:
X	  case 47:
X	  case 48:
X	  case 49:
X	  case 50:
X	  case 51:
X	  case 52:
X	  case 53:
X	  case 54:
X	  case 55:
X	  case 56:
X	  case 57:
X	  case 58:
X	  case 59:
X	  case 60:
X	  case 61:
X	  case 62:
X	  case 63:	return 6;
X
X	  case 64:
X	  case 65:
X	  case 66:
X	  case 67:
X	  case 68:
X	  case 69:
X	  case 70:
X	  case 71:
X	  case 72:
X	  case 73:
X	  case 74:
X	  case 75:
X	  case 76:
X	  case 77:
X	  case 78:
X	  case 79:
X	  case 80:
X	  case 81:
X	  case 82:
X	  case 83:
X	  case 84:
X	  case 85:
X	  case 86:
X	  case 87:
X	  case 88:
X	  case 89:
X	  case 90:
X	  case 91:
X	  case 92:
X	  case 93:
X	  case 94:
X	  case 95:
X	  case 96:
X	  case 97:
X	  case 98:
X	  case 99:
X	  case 100:
X	  case 101:
X	  case 102:
X	  case 103:
X	  case 104:
X	  case 105:
X	  case 106:
X	  case 107:
X	  case 108:
X	  case 109:
X	  case 110:
X	  case 111:
X	  case 112:
X	  case 113:
X	  case 114:
X	  case 115:
X	  case 116:
X	  case 117:
X	  case 118:
X	  case 119:
X	  case 120:
X	  case 121:
X	  case 122:
X	  case 123:
X	  case 124:
X	  case 125:
X	  case 126:
X	  case 127:	return 7;
X	
X	default:	return 8;
X	} 
X	} 
X
X
X
X/* ----------------------------------------------------------- */
X
XExpand(c)
Xint c;
X	{ 
X#define DLE		144
X	
X	switch (ExState) {
X		
X		case 0:
X		 if (c != DLE)
X			OutByte(c);
X		 else 
X			ExState = 1; 
X		break; 
X		
X		case 1:
X		 if (c != 0)
X		 { 
X			V = c; 
X			Len = reduce_L(V);
X			ExState = reduce_F(Len);
X		 } 
X		 else 
X		 { 
X			OutByte(DLE); 
X			ExState = 0; 
X		 } 
X		break; 
X		
X		case 2:	{ 
X			Len = Len + c; 
X			ExState = 3; 
X		 } 
X		break; 
X		
X		case 3:	{ 
X			int i;
X			longint offset = reduce_D(V,c);
X			longint op = outpos - offset;
X
X			for (i = 0; i <= Len + 2; i++) 
X			{ 
X			if (op < 0L) 
X				OutByte(0);
X			else 
X				OutByte(outbuf[(int)(op % sizeof(outbuf))]);
X			op++; 
X			} 
X
X			ExState = 0; 
X		 } 
X	  break;
X	} 
X	} 
X
X
X/* ----------------------------------------------------------- */
X	
XLoadFollowers()
X	{ 
X	int	x;
X	int	i;
X	int	b;
X
X	for (x = 255; x >= 0; x--) 
X	{ 
X	  ReadBits(6,&b); 
X	  Slen[x] = b;
X
X	  for (i = 0; i < Slen[x]; i++)
X	  { 
X		ReadBits(8,&b); 
X		followers[x][i] = b;
X	  } 
X	} 
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 */ 
X
XunReduce()
X	/* expand probablisticly reduced data */ 
X
X	{ 
X
X	int	lchar;
X	int	lout;
X	int	I;
X
X	factor = cmethod - 1; 
X
X	if ((factor < 1) || (factor > 4)) 
X	{ 
X	skip_csize(); 
X	return;
X	} 
X
X	ExState = 0; 
X	LoadFollowers(); 
X	lchar =  0;
X
X	while ((!zipeof) && (outpos < cusize))
X	{ 
X
X	if (Slen[lchar] == 0)
X	  ReadBits(8,&lout);
X	else 
X
X	{ 
X	  ReadBits(1,&lout); 
X	  if (lout != 0) 
X		ReadBits(8,&lout);
X	  else 
X	  { 
X		ReadBits(reduce_B(Slen[lchar]),&I);
X		lout = followers[lchar][I];
X	  } 
X	} 
X
X	Expand(lout); 
X	lchar = lout; 
X	} 
X} 
X
X
X/* ------------------------------------------------------------- */
X/*
X * Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm
X * with partial clearing.
X *
X */ 
X
Xpartial_clear()
X{ 
X	int	pr;
X	int	cd;
X
X
X	/* mark all nodes as potentially unused */
X	for (cd = first_ent; cd < free_ent; cd++)
X	prefix_of[cd] |= 0x8000;
X
X
X	/* unmark those that are used by other nodes */
X	for (cd = first_ent; cd < free_ent; cd++)
X	{ 
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
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
X	/* find first cleared node as next free_ent */ 
X	free_ent = first_ent; 
X	while ((free_ent < maxcodemax) && (prefix_of[free_ent] != -1)) 
X	free_ent++; 
X} 
X
X
X/* ------------------------------------------------------------- */
X
XunShrink()
X
X{ 
X	int	stackp;
X	int	finchar;
X	int	code;
X	int	oldcode;
X	int	incode;
X
X
X	/* decompress the file */ 
X	maxcodemax = 1 << max_bits; 
X	cbits = init_bits; 
X	maxcode = (1 << cbits) - 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	{ 
X	prefix_of[code] = 0;
X	suffix_of[code] = code;
X	} 
X
X	ReadBits(cbits,&oldcode); 
X	if (zipeof) return;
X	finchar = oldcode; 
X
X	OutByte(finchar); 
X
X	stackp = 0; 
X
X	while ((!zipeof)) 
X	{ 
X	ReadBits(cbits,&code); 
X	if (zipeof) return;
X
X	while (code == clear)
X	{ 
X	  ReadBits(cbits,&code); 
X
X	  switch (code) {
X		
X		case 1:	{ 
X			cbits++; 
X			if (cbits == max_bits) 
X			maxcode = maxcodemax;
X			else 
X			maxcode = (1 << cbits) - 1; 
X		 } 
X		break;
X
X		case 2:
X			partial_clear();
X		break;
X	  } 
X
X	  ReadBits(cbits,&code); 
X	  if (zipeof) return;
X	} 
X
X	
X	/* special case for KwKwK string */
X	incode = code;
X	if (prefix_of[code] == -1)
X	{ 
X	  stack[stackp] = finchar;
X	  stackp++; 
X	  code = oldcode; 
X	} 
X
X
X	/* generate output characters in reverse order */
X	while (code >= first_ent)
X	{ 
X	  stack[stackp] = suffix_of[code];
X	  stackp++; 
X	  code = prefix_of[code];
X	} 
X
X	finchar = suffix_of[code];
X	stack[stackp] = finchar;
X	stackp++; 
X
X
X	/* and put them out in forward order */
X	while (stackp > 0)
X	{ 
X	  stackp--; 
X	  OutByte(stack[stackp]);
X	} 
X
X
X	/* generate new entry */
X	code = free_ent;
X	if (code < maxcodemax) 
X	{ 
X	  prefix_of[code] = oldcode;
X	  suffix_of[code] = finchar;
X	  while ((free_ent < maxcodemax) && (prefix_of[free_ent] != -1))
X		free_ent++;
X	} 
X
X
X	/* remember previous code */
X	oldcode = incode; 
X	} 
X
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xextract_member()
X{ 
X	int	b;
X
Xfor (b=0; b<sizeof(outbuf); b++) outbuf[b]=0;
X	pcbits = 0; 
X	incnt = 0; 
X	outpos = 0L; 
X	outcnt = 0; 
X	zipeof = 0;
X
X
X	if (test_zip == 0) {
X		outfd = creat(filename,S_IWRITE|S_IREAD);
X		if (outfd < 1)
X		{ 
X			printf("Can't create output: %s\n",filename); 
X			exit(1);
X		} 
X		close(outfd);
X		outfd = open(filename,O_RDWR);
X	}
X
X	if (test_zip)
X		printf(" Testing: %s ...",filename);
X
X	switch (cmethod) {
X	
X	case 0:	/* stored */ 
X		{ 
X		 if (test_zip == 0)
X		 	printf(" Extract: %s ...",filename); 
X		 while ((!zipeof)) 
X		 { 
X			ReadByte(&b); 
X			OutByte(b); 
X		 } 
X		} 
X	break; 
X	
X	case 1:	{ 
X		 if (test_zip == 0)
X		 	printf("UnShrink: %s ...",filename); 
X		 unShrink(); 
X		} 
X	break; 
X	
X	case 2:	
X	case 3:	
X	case 4:	
X	case 5:	{ 
X		 if (test_zip == 0)
X		 	printf("  Expand: %s ...",filename); 
X		 unReduce(); 
X		} 
X	break; 
X	
X	default: printf("Unknown compression method."); 
X	} 
X
X	if (outcnt > 0) {
X		if (test_zip == 0)
X			write(outfd,outbuf,outcnt);
X		addbfcrc (outbuf, outcnt);
X	}
X
X	if (test_zip == 0)
X		close(outfd);
X
X	if ((crccode + lrec.crc32) == -1)
X		printf("  Ok");
X	else
X		printf("  Bad");
X
X	if (verbose)
X		printf(" [%d]\n",crccode);
X	else
X		printf("\n");
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
X/* UNIX support routines: Michael Enkelis */
Xget_byte()
X{
X	unsigned int nibble;
X	read(zipfd,&nibble,1);
X	return (nibble & 0xff);
X}
X
Xget_word()
X{
X	unsigned int nibble[2];
X		nibble[0] = get_byte();
X		nibble[1] = get_byte();
X	return (int) (nibble[0] | nibble[1] << 8);
X}
X
Xget_long()
X{
X	unsigned int nibble[4];
X		nibble[0] = get_byte();
X		nibble[1] = get_byte();
X		nibble[2] = get_byte();
X		nibble[3] = get_byte();
X	return (long)	((unsigned long) nibble[0] |
X			((unsigned long) nibble[1] << 8)  |
X			((unsigned long) nibble[2] << 16) |
X			((unsigned long) nibble[3] << 24));
X}
X/** End of added support routines **/
X
Xprocess_local_file_header()
X{ 
X	lrec.version_needed_to_extract = get_word();
X	lrec.general_purpose_bit_flag = get_word();
X	lrec.compression_method = get_word();
X	lrec.last_mod_file_time = get_word();
X	lrec.last_mod_file_date = get_word();
X	lrec.crc32 = get_long();
X	lrec.compressed_size = get_long();
X	lrec.uncompressed_size = get_long();
X	lrec.filename_length = get_word();
X	lrec.extra_field_length = get_word();
X
X	get_string(lrec.filename_length,filename);
X	get_string(lrec.extra_field_length,extra);
X
X	if (debugging) {
X	printf("Version used	: %d\n",lrec.version_needed_to_extract);
X	printf("Bit flags	: %d\n",lrec.general_purpose_bit_flag);
X	printf("Compression 	: %d\n",lrec.compression_method);
X	printf("Mod time	: %d\n",lrec.last_mod_file_time);
X	printf("Mod date	: %d\n",lrec.last_mod_file_date);
X	printf("Crc32		: %d\n",~lrec.crc32);
X	printf("Compressed size	: %d\n",lrec.compressed_size);
X	printf("Normal file size: %d\n",lrec.uncompressed_size);
X	printf("File name	: %s.%s\n",filename,extra);
X	}
X
X	csize = lrec.compressed_size;
X	cusize = lrec.uncompressed_size;
X	cmethod = lrec.compression_method;
X
X 	crccode = INITCRC;
X	extract_member(); 
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xprocess_central_file_header()
X{ 
X	central_directory_file_header rec; 
X	char filename[STRSIZ];
X	char extra[STRSIZ];
X	char comment[STRSIZ];
X
X	rec.version_made_by = get_word();
X	rec.version_needed_to_extract = get_word();
X	rec.general_purpose_bit_flag = get_word();
X	rec.compression_method = get_word();
X	rec.last_mod_file_time = get_word();
X	rec.last_mod_file_date = get_word();
X	rec.crc32 = get_long();
X	rec.compressed_size = get_long();
X	rec.uncompressed_size = get_long();
X	rec.filename_length = get_word();
X	rec.extra_field_length = get_word();
X	rec.file_comment_length = get_word();
X	rec.disk_number_start = get_word();
X	rec.internal_file_attributes = get_word();
X	rec.external_file_attributes = get_long();
X	rec.relative_offset_local_header = get_long();
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
X	crccode = INITCRC;
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xprocess_end_central_dir()
X{ 
X	end_central_dir_record rec; 
X	char comment[STRSIZ];
X
X	rec.number_this_disk = get_word();
X	rec.number_disk_with_start_central_directory = get_word();
X	rec.total_entries_central_dir_on_this_disk = get_word();
X	rec.total_entries_central_dir = get_word();
X	rec.size_central_directory = get_long(); 
X	rec.offset_start_central_directory = get_long();
X	rec.zipfile_comment_length = get_word();
X
X	get_string(rec.zipfile_comment_length,comment); 
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xprocess_headers()
X{ 
X	longint sig;
X
X	while (1)
X	{ 
X	if (read(zipfd,&sig,sizeof(sig)) != sizeof(sig))
X	  return;
X	else 
X
X	if (sig == local_file_header_signature) 
X	  process_local_file_header();
X	else 
X
X	if (sig == central_file_header_signature) 
X	  process_central_file_header();
X	else 
X
X	if (sig == end_central_dir_signature) 
X	{ 
X	  process_end_central_dir(); 
X	  return;
X	} 
X
X	else 
X	{ 
X	  printf("Invalid Zipfile Header\n"); 
X	  return;
X	} 
X	} 
X
X} 
X
X
X/* ---------------------------------------------------------- */ 
X
Xextract_zipfile()
X{ 
X	zipfd = open(zipfn,O_RDONLY);
X	if (zipfd < 1) {
X	printf("Can't open input file: %s\n",zipfn);
X	return;
X	}
X
X	process_headers();
X 
X	close(zipfd);
X} 
X
X
X/* ---------------------------------------------------------- */
X/*
X * main program
X *
X */ 
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int c;				/* next option letter */
X	int count = 0;			/* count of required options seen */
X
X	extern int optind;		/* from getopt: next arg to process */
X	extern int opterr;		/* used by getopt */
X	extern char *optarg;
X
X	opterr = 0;			/* so getopt won't print err msg */
X
X	printf("\n"); 
X	printf("%s\n",version); 
X	printf("Courtesy of: S.H.Smith and The Tool Shop BBS,(602) 279-2673.");
X	printf("\nModified by Sanford <Sandy> Zelkovitz - XBBS - (714) 898-8634");
X	printf("\n\n");
X
X	while ((c = getopt (argc, argv, "dtv")) != EOF)
X	{
X	switch (c) {
X		case 'd':	debugging++; break;
X		case 't':	test_zip++; break;
X		case 'v':	verbose++; break;
X		default:	short_help();
X		}
X	}
X
X	strcpy(zipfn,argv[optind]);
X	if (strlen(zipfn) == 0)
X		short_help();
X
X	if (strchr(zipfn,'.') == NULL)
X	strcat(zipfn,".zip");
X
X	extract_zipfile(); 
X
X	exit(0);
X}
X
Xshort_help()
X{
X	printf("Usage:	UnZip -tv file[.zip]\n");
X	exit(1);
X}
SHAR_EOF
chmod 0644 unzipbsd.c || echo "restore of unzipbsd.c fails"
exit 0

bturner@hpcvlx.HP.COM (Bill Turner) (04/12/89)

The only problem with both the original Unzip posting and this was that they
were written for byte-swapping architectures.  If you want to have it work
on non-byte-swapping systems, apply the following changes:

1) All of the signature values need to be byte-swapped.  I.e.,

	local_file_header_signature is 0x504b0304L
	central_file_header_signature is 0x504b0102L
	end_central_dir_signature is 0x504b0506L

2) In the routine get_byte, declare nibble as unsigned char rather than
   unsigned int.

----Bill Turner 
HP Corvallis Workstation Operation

swh@hpsmtc1.HP.COM (Steve Harrold) (04/13/89)

Re: The UNZIP program

Thank you for the "byte-swapped" and "nibble" corrections.

An additional correction is that the declaration for the "get_long()"
function should be "longint" rather than the default "int".  Failure to
do this ensures that the code calculates bad CRC32 checks on a machine
that has 16-bit ints.  The zip file is successfully extracted, but you
get a series of unsettling "bad" messages.

Furthermore, the "open()" functions have to set the file mode to include
the "O_BINARY" attribute for those environments that distinguish "text"
files from "binary" files (e.g. MSDOS).

An additional question is the use of the symbol "L_SET" in the original
posting.  This has a value of 0 (from file "file.h") but I think the 
symbol L_INCR (value = 1) should be used.  The XENIX adaptation sets
L_SET = 1 to achieve this purpose.

Can the original author comment on these fixes?