home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume23
/
zip
/
part01
next >
Wrap
Text File
|
1991-10-21
|
55KB
|
1,599 lines
Newsgroups: comp.sources.misc
From: kirsch@usasoc.soc.mil (David Kirschbaum)
Subject: v23i088: zip - Portable zip v1.0, Part01/09
Message-ID: <csm-v23i088=zip.231424@sparky.IMD.Sterling.COM>
X-Md4-Signature: 61134dcb2a8c2cb49e9e129416f582d3
Date: Mon, 21 Oct 1991 04:20:22 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: kirsch@usasoc.soc.mil (David Kirschbaum)
Posting-number: Volume 23, Issue 88
Archive-name: zip/part01
Environment: UNIX, Minix, MSDOS, OS/2, VMS
Here's the product of the Info-ZIP Workgroup: a portable, generic
compatible zip file compressor. This is a companion to the unzip utility
also distributed by this group.
I extracted the original zip10ex.zip distribution files, changed them all
to Unix end_of_line, lower-cased a bunch of the file names (just to give
the Unix systems something familiar), and used cshar (comp.sources.unix
volume15) to create the Partnn shar files. Other than those minor changes
(for transmission only), all honor and glory to the original authors.
(Be sure to contact *them* (or Info-ZIP@valeria.cs.ucla.edu) if there
are any bugs or problems.)
Oh, yes, this is the *export* version (no encryption). The domestic
version (with encryption) is not available for general distribution
(because of various Federal regulations). No, you don't want to know.
Following is the README file from the original zip10ex.zip distribution.
David Kirschbaum
Info-ZIP Coordinator
kirsch@usasoc.soc.mil
===
Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
Permission is granted to any individual or institution to use, copy, or
redistribute this software so long as all of the original files are included
unmodified, that it is not sold for profit, and that this copyright notice
is retained.
LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
RESULTING FROM THE USE OF THIS SOFTWARE.
Please read the file zip.doc for information on how to compile, install, and
use zip, zipcloak (if this is not an export version), zipsplit, zipnote, and
ship. The file "contents" is a complete list of the files you should have in
this distribution. Also, if you are using MSDOS, you should read the note on
file formats at the end of the contents file.
----------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents: README im_ctree.c makevms.com
# Wrapped by kent@sparky on Sun Oct 20 22:58:51 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 9)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(929 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XCopyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
XPermission is granted to any individual or institution to use, copy, or
Xredistribute this software so long as all of the original files are included
Xunmodified, that it is not sold for profit, and that this copyright notice
Xis retained.
X
XLIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
XPROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
XIMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
XRESULTING FROM THE USE OF THIS SOFTWARE.
X
XPlease read the file zip.doc for information on how to compile, install, and
Xuse zip, zipcloak (if this is not an export version), zipsplit, zipnote, and
Xship. The file "contents" is a complete list of the files you should have in
Xthis distribution. Also, if you are using MSDOS, you should read the note on
Xfile formats at the end of the contents file.
END_OF_FILE
if test 929 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'im_ctree.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'im_ctree.c'\"
else
echo shar: Extracting \"'im_ctree.c'\" \(45523 characters\)
sed "s/^X//" >'im_ctree.c' <<'END_OF_FILE'
X/*
X
X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
X Permission is granted to any individual or institution to use, copy, or
X redistribute this software so long as all of the original files are included
X unmodified, that it is not sold for profit, and that this copyright notice
X is retained.
X
X*/
X
X/*
X * im_ctree.c by Richard B. Wales.
X *
X * Includes modifications by Jean-Loup Gailly.
X *
X * PURPOSE
X *
X * Encode various sets of source values using variable-length
X * binary code trees.
X *
X * DISCUSSION
X *
X * The PKZIP "implosion" process uses several variable-depth binary
X * code trees, similar to Huffman trees. The more common source
X * values are represented by shorter bit sequences.
X *
X * Each code tree is stored in the ZIP file in a compressed form
X * that is essentially a run-length-encoded list of the lengths of
X * all the code strings (in ascending order by source values).
X * The actual code strings are reconstructed from the lengths in
X * the UNZIP process, as described in the "application note"
X * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
X *
X * Because of the way a code tree is stored in the ZIP file, the
X * codes must conform to the following restrictions:
X *
X * (1) No code string may ever exceed 16 bits in length.
X *
X * (2) If all code strings are extended to 16 bits by padding on
X * the right (low-order end) with zeros, and then treated as
X * unsigned 16-bit integers, then:
X *
X * (a) The arithmetically higher 16-bit values must correspond
X * to the shorter code strings.
X *
X * (b) If two source values map into code strings of the same
X * length, the higher code string must correspond to the
X * lower source value (where source values are treated as
X * unsigned).
X *
X * Further, shortcuts taken by PKUNZIP 1.10 in the way it decodes
X * the compressed data via the trees impose the following extra
X * limitations:
X *
X * (3) No code string in the "distance" tree can be longer than 8
X * bits.
X *
X * (4) The maximum length of any code string is limited by the
X * number of initial zero bits, as follows:
X *
X * (a) 0-3 leading zeros: maximum length is 8.
X *
X * (b) 4-5 leading zeros: maximum length is 12.
X *
X * (c) 6-7 leading zeros: maximum length is 14.
X *
X * (5) In the "literal" tree, the code string corresponding to the
X * source value 255 must be at least 10 bits in length, regard-
X * less of the frequency of the value 255 in the file.
X *
X * PKWARE calls the code trees "Shannon-Fano trees". (Shannon-Fano
X * coding was a predecessor to the better-known Huffman coding
X * technique; see the references below.) Although it appears that
X * the Shannon-Fano (top-down partitioning) algorithm is in fact
X * used by PKZIP in the process of creating the code trees, the
X * resulting trees are not in fact "pure" Shannon-Fano, because of
X * the extra processing required in order to meet the restrictions
X * described above.
X *
X * REFERENCES
X *
X * Lynch, Thomas J.
X * Data Compression: Techniques and Applications, pp. 53-55.
X * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
X *
X * Storer, James A.
X * Data Compression: Methods and Theory, pp. 49-50.
X * Computer Science Press, 1988. ISBN 0-7167-8156-5.
X *
X * INTERFACE
X *
X * ImpErr ct_init (void)
X * Initialize the code tree routines. This routine must be
X * called before any other code tree routines may be called.
X *
X * ImpErr ct_tally (MATCH *ma)
X * Tally a "string match" data set. The tally results will be
X * used to determine how large the imploded result will be.
X *
X * ImpErr ct_mktrees (FDATA *fd)
X * Construct all code trees, and then determine how big the
X * imploded file will be under both "literal tree" and "no
X * literal tree" conditions. Choose the best option.
X *
X * ImpErr ct_wrtrees (FILE *outfp)
X * Output the code trees to the ZIP file.
X *
X * ImpErr ct_wrdata (FILE *outfp)
X * Output the file data to the ZIP file.
X *
X * ImpErr ct_windup (void)
X * Deallocate all code trees.
X */
X
X
X#ifdef DEBUG
X# define VALIDATE
X#endif /* DEBUG */
X
X#include "implode.h"
X
X
X/***********************************************************************
X *
X * Local data used by the "code tree" routines.
X */
X
X
X/* Data structure describing a single value and its code string. */
Xtypedef
Xstruct ct_data
X { UL_INT ct_freq; /* frequency count */
X US_INT ct_code; /* bit string */
X U_CHAR ct_len; /* length of bit string */
X U_CHAR ct_val; /* source value */
X }
X TRDATA;
X
X
X/*
X * Data structure for re-sorting source values by bit string length;
X * used during tree generation.
X */
Xtypedef
Xstruct ct_resort
X { U_CHAR ct_rlen; /* length of bit string */
X U_CHAR ct_rval; /* source value */
X#ifdef VMS
X US_INT dummy; /* because of bug in qsort() */
X#endif /* VMS */
X }
X RESORT;
X
X
X/* Header for a code tree. */
Xtypedef
Xstruct ct_desc
X { TRDATA *ct_array; /* array of TRDATA */
X int ct_size; /* # of entries in tree */
X }
X TRDESC;
X
X
X/*
X * Currently active code trees.
X * We allow for five trees (one literal tree, two length trees, and
X * two distance trees) so that we can evaluate the total compression
X * with or without the use of the literal tree. Remember that the
X * minimum matching distance depends on whether or not a literal tree
X * is used; hence, the "length" and "distance" trees will differ.
X */
X#define MAXTREES 5 /* max # of trees at once */
Xlocal TRDESC ct_table[MAXTREES];
X
X
X/* Macro to validate a code tree handle. */
X#define VALID_HANDLE(x) \
X ((x) >= 0 && (x) < MAXTREES && ct_table[x].ct_array != NULL)
X
X
X/*
X * Assorted frequency counts.
X * The "Minimum Match Length" (MML) is 2 if a "literal character" code
X * tree is not used, or 3 if a "literal character" tree is used. Thus,
X * we need to keep two sets of "length" and "distance" frequency counts.
X * Also, 2-character matches need to be counted separately; depending
X * on whether a "literal character" tree is used or not, these will be
X * processed either as literal characters or as distance/length pairs.
X */
X
X/* Total number of source values from Pass One. */
Xlocal long ct_litc_num; /* total # literal chars */
Xlocal long ct_lit2_num; /* total # of 2-char matches */
Xlocal long ct_strg_num; /* total # of string matches */
X
X/* Source value frequencies for the five trees. */
Xlocal long ct_litc_freq[256]; /* literal character freqs */
Xlocal long ct_len2_freq[64]; /* length freqs (MML=2) */
Xlocal long ct_len3_freq[64]; /* length freqs (MML=3) */
Xlocal long ct_dst2_freq[64]; /* distance freqs (MML=2) */
Xlocal long ct_dst3_freq[64]; /* distance freqs (MML=3) */
X
X/* Number of bits saved by using each of the trees. */
Xlocal long ct_litc_saved; /* literal tree */
Xlocal long ct_len2_saved; /* length tree (MML=2) */
Xlocal long ct_len3_saved; /* length tree (MML=3) */
Xlocal long ct_dst2_saved; /* distance tree (MML=2) */
Xlocal long ct_dst3_saved; /* distance tree (MML=3) */
X
X/* Handles for the code trees to be used. */
Xlocal int ct_litc_tree; /* temp literal tree */
Xlocal int ct_len2_tree; /* temp length tree (MML=2) */
Xlocal int ct_len3_tree; /* temp length tree (MML=3) */
Xlocal int ct_dst2_tree; /* temp distance tree (MML=2) */
Xlocal int ct_dst3_tree; /* temp distance tree (MML=3) */
Xlocal int lit_tree; /* literal tree (-1 if none) */
Xlocal int len_tree; /* length tree */
Xlocal int dst_tree; /* distance tree */
X
X
X/***********************************************************************
X *
X * Local (static) routines in this file.
X */
X
Xlocal ImpErr ct_alloc
X OF ((int size, int *handle));
X
Xlocal ImpErr ct_free
X OF ((int handle));
X
Xlocal ImpErr ct_loadf
X OF ((int handle, long *freq));
X
Xlocal ImpErr ct_ziprep
X OF ((int handle, U_CHAR **result));
X
Xlocal ImpErr ct_gencodes
X OF ((int handle, int minbits, int maxbits, long *saved));
X
Xlocal ImpErr ct_split
X OF ((TRDATA *part, int size, long freq,
X int prefix, int preflen, int minbits, int maxbits));
X
Xlocal int ct_fsort
X OF ((TRDATA *tr1, TRDATA *tr2));
X
Xlocal int ct_rsort
X OF ((RESORT *cr1, RESORT *cr2));
X
X
X/***********************************************************************
X *
X * Allocate a code tree.
X */
X
Xlocal
XImpErr
Xct_alloc (size, handle)
X int size;
X int *handle;
X{ register TRDATA *ct;
X int n;
X
X#ifdef VALIDATE
X /* Validate the arguments. */
X if (size < 2 || size > 256) goto badarg;
X if (handle == NULL) goto badarg;
X#endif /* VALIDATE */
X
X /* Allocate an available code tree handle. */
X for (n = 0;
X n < MAXTREES && ct_table[n].ct_array != NULL;
X n++) ;
X if (n >= MAXTREES) return IM_NOCTBLS;
X *handle = n;
X ct_table[n].ct_size = size;
X
X /* Allocate space for the code tree. */
X ct = (TRDATA *) malloc ((unsigned) (size * sizeof (TRDATA)));
X if (ct == NULL) return IM_NOMEM;
X ct_table[n].ct_array = ct;
X
X /* Initialize the code tree. */
X for (n = 0; n < size; n++, ct++)
X { ct->ct_freq = 0;
X ct->ct_code = 0;
X ct->ct_val = (U_CHAR)n;
X ct->ct_len = 0;
X }
X
X /* That's all. */
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_alloc: bad argument(s)");
X return IM_BADARG;
X#endif /* VALIDATE */
X}
X
X
X/***********************************************************************
X *
X * Free a code tree.
X */
X
Xlocal
XImpErr
Xct_free (handle)
X int handle;
X{
X#ifdef VALIDATE
X /* Validate the argument. */
X if (!VALID_HANDLE (handle)) goto badarg;
X#endif /* VALIDATE */
X
X /* Free the code tree. */
X free ((char *) ct_table[handle].ct_array);
X ct_table[handle].ct_array = NULL;
X ct_table[handle].ct_size = 0;
X
X /* That's all. */
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_free: bad argument(s)");
X return IM_BADARG;
X#endif /* VALIDATE */
X}
X
X
X/***********************************************************************
X *
X * Update a code tree with frequency data.
X *
X * In order to allow for the later addition of "adaptive" coding,
X * the new frequencies are added to the existing data.
X */
X
Xlocal
XImpErr
Xct_loadf (handle, freq)
X int handle;
X long *freq;
X{ register long *f;
X register TRDATA *ct;
X int n;
X
X#ifdef VALIDATE
X /* Validate the arguments. */
X if (!VALID_HANDLE (handle)) goto badarg;
X#endif /* VALIDATE */
X
X /* Add in the frequencies. */
X for (f = freq,
X ct = ct_table[handle].ct_array,
X n = ct_table[handle].ct_size;
X n > 0;
X f++, ct++, n--)
X ct->ct_freq += *f;
X
X /* That's all. */
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_loadf: bad argument(s)");
X return IM_BADARG;
X#endif /* VALIDATE */
X}
X
X
X/***********************************************************************
X *
X * Generate the ZIP-file representation for a code tree.
X *
X * The returned "result" value points to static data which will be
X * overwritten on the next call to "ct_ziprep".
X *
X * The length of the result string is implicit in the first byte of
X * the value, as specified in the PKZIP applications note.
X */
X
X#ifdef IMPDEBUG
Xchar *treename;
X#endif /* IMPDEBUG */
X
Xlocal
XImpErr
Xct_ziprep (handle, result)
X int handle;
X U_CHAR **result;
X{ static U_CHAR buffer[257]; /* result info */
X register U_CHAR *c;
X register TRDATA *ct;
X int s, n, l;
X
X#ifdef VALIDATE
X /* Validate the arguments. */
X if (!VALID_HANDLE (handle)) goto badarg;
X if (result == NULL) goto badarg;
X#endif /* VALIDATE */
X
X#ifdef IMPDEBUG
X if (treename != NULL && treename[0] != 0)
X { /* Print the code tree info. */
X fprintf (stderr, "\n%s tree:\n value len string\n",
X treename);
X for (ct = ct_table[handle].ct_array,
X s = ct_table[handle].ct_size,
X n = 0;
X s > 0;
X ct++, n++, s--)
X fprintf (stderr, " %3d (%02x) %2d %04x (rev %04x)\n",
X n, n, ct->ct_len,
X bi_reverse(ct->ct_code << (16 - ct->ct_len),
X ct->ct_len) << (16 - ct->ct_len),
X ct->ct_code);
X }
X#endif /* IMPDEBUG */
X
X /* Generate the returned value. */
X for (c = buffer+1,
X ct = ct_table[handle].ct_array,
X s = ct_table[handle].ct_size,
X n = 0,
X l = ct->ct_len;
X s > 0;
X ct++, s--)
X { if (l < 1 || l > 16)
X { fprintf (stderr, "\nError in ct_ziprep: bad code length");
X return IM_LOGICERR;
X }
X if (n >= 16 || (int)ct->ct_len != l)
X { *c++ = (U_CHAR)((((n-1) << 4) & 0xf0) | ((l-1) & 0x0f));
X n = 1; l = ct->ct_len;
X }
X else n++;
X }
X if (n > 0)
X *c++ = (U_CHAR)((((n-1) << 4) & 0xf0) | ((l-1) & 0x0f));
X buffer[0] = (U_CHAR)((c - buffer) - 2);
X
X /* That's all. */
X *result = buffer;
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_ziprep: bad argument(s)");
X return IM_BADARG;
X#endif /* VALIDATE */
X}
X
X
X/***********************************************************************
X *
X * Look up the code string for a given value.
X */
X
X#define ct_lookup(handle, value, string, length) \
X{ register TRDATA *ct; \
X ct = ct_table[handle].ct_array + (value); \
X string = ct->ct_code; \
X length = ct->ct_len; \
X}
X
X
X/***********************************************************************
X *
X * Generate the codes for a code tree. If old codes already exist for
X * the tree, they are discarded, and a new set of codes is generated
X * from scratch.
X * IN assertion: ma_buf is already allocated and can be overwritten.
X */
X
Xlocal
XImpErr
Xct_gencodes (handle, minbits, maxbits, saved)
X int handle; /* which tree */
X int minbits; /* min code string bit length */
X int maxbits; /* max code string bit length */
X long *saved; /* how many bits saved */
X{ register TRDATA *ct;
X TRDATA *ct2;
X register int n;
X UL_INT f;
X register RESORT *cr;
X int code, srclen;
X long totalfreq, totalbits;
X ImpErr retcode;
X RESORT rbuf[256];
X int size; /* alias for ct_table[handle].ct_size */
X int z; /* index of zero frequency element */
X int nz; /* index of non zero frequency element */
X
X#ifdef VALIDATE
X /* Validate the arguments. */
X if (!VALID_HANDLE (handle)) goto badarg;
X if (minbits < 1) goto badarg;
X if (maxbits > 16) goto badarg;
X if (maxbits < minbits) goto badarg;
X if (saved == NULL) goto badarg;
X#endif /* VALIDATE */
X size = ct_table[handle].ct_size;
X
X /*
X * Start by sorting the data by frequency. The source values with
X * higher frequency need to get the shorter Shannon-Fano codes.
X * First exclude the elements with zero frequency, to speed up the sort.
X * This optimization is very important for small files, otherwise the sort
X * takes most of the implode time.
X * Also determine the total of all frequencies. This will be needed in
X * order to partition the source values in the Shannon-Fano bit
X * string computation. Finally clear the "code" (bit string) and "len"
X * (bit string length) fields in the code tree array.
X */
X totalfreq = 0;
X ct = ct_table[handle].ct_array;
X /* Copy ct into a tempo */
X ct2 = (TRDATA*) ma_buf;
X memcpy((char*)ct2, (char*)ct, size * sizeof(TRDATA));
X for (nz = 0, z = n = size-1; n >= 0; n--) {
X int m;
X if (ct2[n].ct_freq != 0L) {
X m = nz++;
X totalfreq += (ct[m].ct_freq = ct2[n].ct_freq);
X } else {
X m = z--;
X ct[m].ct_freq = 0L;
X }
X ct[m].ct_code = 0;
X ct[m].ct_len = 0;
X ct[m].ct_val = (U_CHAR)n; /* ct2[n].ct_val */
X }
X qsort ((char *) (ct_table[handle].ct_array), nz,
X sizeof (TRDATA), (int (*)())ct_fsort);
X
X /*
X * Generate the bit strings via a Shannon-Fano (top-down) algorithm.
X */
X retcode =
X ct_split (ct_table[handle].ct_array, /* partition start */
X size, /* partition size */
X totalfreq, /* total frequency */
X 0, /* code string prefix */
X 0, /* # bits in prefix */
X minbits, /* minimum tree depth */
X maxbits); /* maximum tree depth */
X if (retcode != IM_OK) return retcode;
X
X /*
X * The source value 255 needs to be assigned a bit string with a
X * length of at least 10, in order to accommodate shortcuts in
X * PKUNZIP's decoding algorithm. If no bit string in the tree is
X * of length 10, we assign 255 to the longest string and hope for
X * the best.
X */
X n = size;
X if (n == 256)
X { for (ct = ct_table[handle].ct_array;
X n > 0 && ct->ct_val != 255;
X n--, ct++) ;
X if (n == 0)
X { fprintf (stderr, "\nError in ct_gencodes: no value 255");
X return IM_LOGICERR;
X }
X if (ct->ct_len < 10)
X { ct2 = ct;
X while (n > 0 && ct->ct_len < 10) n--, ct++;
X if (n == 0) ct--; /* no len>=10 in tree; use longest */
X n = ct->ct_val;
X ct->ct_val = ct2->ct_val;
X ct2->ct_val = (U_CHAR)n;
X f = ct->ct_freq;
X ct->ct_freq = ct2->ct_freq;
X ct2->ct_freq = f;
X } }
X
X /*
X * The source values need to be re-sorted so that all source values
X * with code strings of the same length will be in ascending order.
X * This is because of the compression scheme used to represent the
X * tree in the ZIP file.
X */
X for (n = size,
X ct = ct_table[handle].ct_array,
X cr = rbuf;
X n > 0;
X n--, ct++, cr++)
X { cr->ct_rlen = ct->ct_len;
X cr->ct_rval = ct->ct_val;
X }
X n = size;
X qsort ((char *) rbuf, n, sizeof (RESORT), (int (*)())ct_rsort);
X for (ct = ct_table[handle].ct_array,
X cr = rbuf;
X n > 0;
X n--, ct++, cr++)
X ct->ct_val = cr->ct_rval;
X
X#ifdef DUMP_TREE
X printf ("Finished tree:\n");
X for (n = size,
X ct = ct_table[handle].ct_array;
X n > 0;
X n--, ct++)
X printf (" %3d (0x%02x) l %2d c 0x%04x f %ld\n",
X ct->ct_val, ct->ct_val, ct->ct_len, ct->ct_code, ct->ct_freq);
X putchar ('\n');
X#endif /* DUMP_TREE */
X
X /*
X * Finally, sort the tree back in ascending order by source value
X * -- which is the order expected by other portions of the program.
X */
X ct = ct_table[handle].ct_array;
X /* Copy ct into a tempo */
X ct2 = (TRDATA*)ma_buf;
X memcpy((char*)ct2, (char*)ct, size * sizeof(TRDATA));
X for (n = size-1; n >= 0; n--) {
X U_CHAR v = ct2[n].ct_val;
X ct[v].ct_freq = ct2[n].ct_freq;
X ct[v].ct_code = ct2[n].ct_code;
X ct[v].ct_len = ct2[n].ct_len;
X ct[v].ct_val = v;
X }
X
X /*
X * Determine how many bits will be saved if all the source data is
X * encoded using this new set of code strings, as opposed to being
X * represented directly in unencoded form.
X */
X /* # of bits needed for unencoded source values */
X n = ct_table[handle].ct_size;
X for (code = 1, srclen = 0; code < n; code <<= 1, srclen++) ;
X /* # of bits used if all source values encoded via this tree */
X for (ct = ct_table[handle].ct_array,
X totalbits = 0;
X n > 0;
X n--, ct++)
X totalbits += ct->ct_freq * ct->ct_len;
X /* # bits saved by using the tree */
X *saved = (totalfreq * srclen) - totalbits;
X
X /* That's all. */
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_gencodes: bad argument(s)");
X return IM_BADARG;
X#endif /* VALIDATE */
X}
X
X
X/***********************************************************************
X *
X * Split a portion of a code tree into two pieces of approximately equal
X * total frequency. This routine calls itself recursively in order to
X * generate the bit strings for the entire code tree.
X */
X
Xlocal
XImpErr
Xct_split (part, size, freq, prefix, preflen, minbits, maxbits)
X TRDATA *part; /* start of partition */
X int size; /* # elements in partition */
X long freq; /* sum of frequencies in partition */
X int prefix; /* initial code bits for partition */
X int preflen; /* # bits in prefix */
X int minbits; /* minimum permissible bit length */
X int maxbits; /* maximum permissible bit length */
X{ register TRDATA *ct;
X int topmaxbits, botmaxbits, localminbits;
X U_INT topmaxvals, botmaxvals;
X int topsize, botsize;
X long topfreq, botfreq, halffreq, onefreq;
X int n, m, leadzeros;
X int maxshort, minlong;
X ImpErr retcode;
X static maxarray[17] =
X { 8,8,8,8,12,12,14,14,16,16,16,16,16,16,16,16,16 };
X
X#ifdef VALIDATE
X if (part == NULL) goto badarg;
X if (size < 1) goto badarg;
X if (freq < 0) goto badarg;
X if (preflen < 0) goto badarg;
X if (preflen > maxbits) goto badarg;
X if (minbits < preflen) goto badarg;
X if (maxbits > 16) goto badarg;
X if (maxbits < minbits) goto badarg;
X /*
X putc ('\n', stderr);
X for (n = preflen; n > 0; n--) fprintf (stderr, " ");
X fprintf (stderr, "ct_split (sz=%d, pr=%04x[%d], min=%d, max=%d)",
X size, prefix, preflen, minbits, maxbits);
X */
X#endif /* VALIDATE */
X
X /*
X * If there's only one element in this partition, we simply take
X * the "prefix" value as the code string for the single element.
X * We reverse the bits of the prefix for more efficient output.
X */
X if (size == 1)
X { part->ct_code = bi_reverse(prefix, preflen);
X part->ct_len = (U_CHAR)preflen;
X return IM_OK;
X }
X
X /*
X * This partition will be divided into two parts. The "top" part
X * will have a "1" bit appended to its "prefix" bit string; the
X * "bottom" part will have a "0" bit appended to its "prefix".
X *
X * We need to determine the maximum number of source values which
X * may be assigned to the two partitions. The first issue to con-
X * sider is that PKUNZIP 1.10's tree-decoding shortcuts require a
X * certain number of leading "0" bits in each code string, depending
X * on its length. Code strings of 9-12 bits must have at least 4
X * leading zeros; strings of 13 or 14 bits, at least 6 leading
X * zeros; and strings of 15 or 16 bits, at least 8 leading zeros.
X *
X * If the "prefix" is zero, the above limitation is used to restrict
X * the maximum size of the top half of the partition. The bottom
X * half does not need to be restricted in this way, since it can be
X * extended as far as needed along the path where the "prefix" grows
X * in length but remains all zero.
X */
X botmaxbits = maxbits;
X if (prefix != 0) topmaxbits = maxbits;
X else
X { for (n = 0, leadzeros = 0x8000;
X n < preflen && (prefix & leadzeros) == 0;
X n++, leadzeros >>= 1) ;
X topmaxbits = maxarray[n];
X if (topmaxbits > maxbits) topmaxbits = maxbits;
X }
X if (topmaxbits < minbits)
X { fprintf (stderr, "\nError in ct_split: ");
X fprintf (stderr, "topmaxbits(%d) < minbits(%d)",
X topmaxbits, minbits);
X goto oops;
X }
X if (botmaxbits < minbits)
X { fprintf (stderr, "\nError in ct_split: ");
X fprintf (stderr, "botmaxbits(%d) < minbits(%d)",
X botmaxbits, minbits);
X goto oops;
X }
X topmaxvals = 1 << (topmaxbits - preflen - 1);
X n = size >> 1; if (topmaxvals > n) topmaxvals = n;
X botmaxvals = 1 << (botmaxbits - preflen - 1);
X n = size - 1; if (botmaxvals > n) botmaxvals = n;
X if (topmaxvals + botmaxvals < size)
X { fprintf (stderr, "\nError in ct_split: ");
X fprintf (stderr, "topmaxvals(%d) + botmaxvals(%d) ",
X topmaxvals, botmaxvals);
X fprintf (stderr, "< size(%d)", size);
X goto oops;
X }
X
X /*
X * We now split the current partition into two halves of as close
X * to equal frequency as possible. If the total of all frequencies
X * in the partition is zero, split into two halves of equal size.
X */
X if (freq == 0)
X { topsize = size >> 1;
X ct = part + topsize;
X topfreq = 0;
X }
X else
X { halffreq = freq >> 1; /* half the total frequency */
X m = size >> 1; /* half the total elements, */
X /* rounded down */
X for (topsize = 0, topfreq = 0, ct = part;
X topsize < m && topfreq <= halffreq
X && (onefreq = ct->ct_freq) > 0;
X topsize++, ct++)
X topfreq += onefreq;
X if (topsize >= 2)
X { /*
X * If moving one element from the top to the bottom parti-
X * tion would make the two more closely equal in frequency,
X * do it.
X */
X onefreq = (ct-1)->ct_freq;
X if ((topfreq - halffreq) > (halffreq - (topfreq - onefreq)))
X ct--, topsize--, topfreq -= onefreq;
X } }
X botsize = size - topsize;
X botfreq = freq - topfreq;
X /* "ct" points to first element in bottom half */
X
X /*
X * The above first-cut attempt to split the partition may not work
X * for one of two reasons. First, one or the other half may contain
X * too many values (more than "topmaxvals" or "botmaxvals").
X */
X while (topsize > topmaxvals)
X { onefreq = (--ct)->ct_freq;
X topsize--; topfreq -= onefreq;
X botsize++; botfreq += onefreq;
X }
X while (botsize > botmaxvals)
X { onefreq = (ct++)->ct_freq;
X topsize++; topfreq += onefreq;
X botsize--; botfreq -= onefreq;
X }
X
X /*
X * Second, the number of bits required to represent the values in
X * each half may violate PKZIP's requirement (implicit in the way
X * trees are compressed in an imploded file) that no code string in
X * the top half may be longer than any code string in the bottom
X * half.
X */
X localminbits = preflen + 1;
X if (localminbits < minbits) localminbits = minbits;
X for (;;)
X { for (maxshort = preflen + 1, n = 1;
X n < botsize;
X maxshort++, n <<= 1) ;
X if (n > botsize) maxshort--;
X if (maxshort < localminbits) maxshort = localminbits;
X if (maxshort > topmaxbits) maxshort = topmaxbits;
X for (minlong = preflen + 1, n = 1;
X n < topsize;
X minlong++, n <<= 1) ;
X if (minlong <= maxshort) break;
X onefreq = (--ct)->ct_freq;
X topsize--; topfreq -= onefreq;
X botsize++; botfreq += onefreq;
X }
X
X /*
X * Third, the number of elements in the top half must be enough to
X * result in each string having at least "minbits" bits in all.
X */
X n = 1 << (minbits - preflen - 1);
X while (topsize < n)
X { onefreq = (ct++)->ct_freq;
X topsize++; topfreq += onefreq;
X botsize--; botfreq -= onefreq;
X }
X
X /*
X * Now that the sizes of the two halves of the partition have been
X * finalized, process the top and bottom halves via recursion.
X */
X retcode = ct_split (part, topsize, topfreq,
X prefix | (1 << (15-preflen)),
X preflen + 1, localminbits, maxshort);
X if (retcode != IM_OK) return retcode;
X ct = part + topsize;
X retcode = ct_split (ct, botsize, botfreq,
X prefix, preflen + 1, (int)ct[-1].ct_len, maxbits);
X if (retcode != IM_OK) return retcode;
X
X /* That's all. */
X return IM_OK;
X
X#ifdef VALIDATE
Xbadarg:
X fprintf (stderr, "\nError in ct_split: bad argument(s)");
X putchar ('\n'); fflush (stdout); fflush (stderr);
X /* abort (); */
X return IM_BADARG;
X#endif /* VALIDATE */
X
Xoops:
X#ifdef VALIDATE
X putchar ('\n'); fflush (stdout); fflush (stderr);
X /* abort (); */
X#endif /* VALIDATE */
X return IM_LOGICERR;
X}
X
X
X/***********************************************************************
X *
X * Sorting function -- descending order by source value frequency.
X *
X * This sorting function is used at the start of the code tree con-
X * struction process, before the bit string values are assigned.
X * To ensure consistent behaviour on all machines, we use the source
X * values as secondary sort key, but this is not mandatory.
X */
X
Xlocal
Xint
Xct_fsort (tr1, tr2)
X TRDATA *tr1, *tr2;
X{ long d;
X int v;
X
X d = (long) tr1->ct_freq - (long) tr2->ct_freq;
X if (d < 0) return 1;
X if (d > 0) return -1;
X v = (int) tr1->ct_val - (int) tr2->ct_val;
X if (v < 0) return 1;
X if (v > 0) return -1;
X return 0;
X}
X
X
X/***********************************************************************
X *
X * Sorting function -- ascending order by bit string length; if lengths
X * are the same, ascending order by source value.
X *
X * This sorting function is used after the bit string values have been
X * assigned.
X */
X
Xlocal
Xint
Xct_rsort (cr1, cr2)
X RESORT *cr1, *cr2;
X{ int d;
X
X d = (int) cr1->ct_rlen - (int) cr2->ct_rlen;
X if (d > 0) return 1;
X if (d < 0) return -1;
X d = (int) cr1->ct_rval - (int) cr2->ct_rval;
X if (d > 0) return 1;
X if (d < 0) return -1;
X return 0;
X}
X
X
X/***********************************************************************
X *
X * Allocate the code trees.
X */
X
XImpErr
Xct_init ()
X{ ImpErr retcode;
X int i;
X
X#ifdef DEBUG
X if (256*sizeof(TRDATA) > MA_BUFSIZE*sizeof(MATCH)) return IM_LOGICERR;
X#endif /* DEBUG */
X
X retcode = ct_windup ();
X if (retcode != IM_OK) return retcode;
X
X ct_litc_num = 0;
X ct_lit2_num = 0;
X ct_strg_num = 0;
X
X for (i = 255; i >= 0; i--)
X ct_litc_freq[i] = 0;
X for (i = 63; i >= 0; i--)
X ct_len2_freq[i] = 0, ct_len3_freq[i] = 0,
X ct_dst2_freq[i] = 0, ct_dst3_freq[i] = 0;
X
X retcode = ct_alloc (256, &ct_litc_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_alloc (64, &ct_len2_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_alloc (64, &ct_len3_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_alloc (64, &ct_dst2_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_alloc (64, &ct_dst3_tree);
X if (retcode != IM_OK) return retcode;
X
X return IM_OK;
X}
X
X
X/***********************************************************************
X *
X * Tally a "string match" data set. The tally results will be used to
X * determine how large the imploded result will be.
X */
X
XImpErr
Xct_tally (ma)
X MATCH *ma; /* match data to write out */
X{ register int ch;
X int dist = ma->ma_dist;
X
X /* Tally up the latest data. */
X if (dist == 0) { /* literal character */
X ct_litc_num++;
X ch = ma->l.ma_litc[0];
X ct_litc_freq[ch]++;
X
X } else if (dist < 0) { /* 2-character match */
X ct_lit2_num++;
X ch = ma->l.ma_litc[0];
X ct_litc_freq[ch]++;
X ch = ma->l.ma_litc[1];
X ct_litc_freq[ch]++;
X ch = ((-dist-1) >> fd.fd_nbits) & 0x3f;
X ct_dst2_freq[ch]++;
X ct_len2_freq[0]++;
X
X } else { /* 3-char or longer match */
X ct_strg_num++;
X ch = ((dist-1) >> fd.fd_nbits) & 0x3f;
X ct_dst3_freq[ch]++;
X /* We defer the update of ct_dst2_freq and ct_len2_freq until
X * ct_mktrees:
X * ct_dst2_freq[ch]++;
X * ch = ma->l.ma_length - 2;
X * if (ch > 63) ch = 63;
X * ct_len2_freq[ch]++;
X */
X ch = ma->l.ma_length - 3;
X if (ch > 63) ch = 63;
X ct_len3_freq[ch]++;
X }
X
X /* That's all. */
X return IM_OK;
X}
X
X
X/***********************************************************************
X *
X * Construct all code trees, and then determine how big the imploded
X * file will be under both "literal tree" and "no literal tree" con-
X * ditions. Choose the best option.
X */
X
XImpErr
Xct_mktrees ()
X{ U_CHAR *c;
X ImpErr retcode;
X register long sum;
X long len2, len3;
X int n;
X
X /* ct_tally did not update ct_dst2_freq and ct_len2_freq for matches of
X * length > 2, so correct this now.
X */
X for (n = 62; n >= 0; n--) {
X ct_dst2_freq[n] += ct_dst3_freq[n];
X ct_len2_freq[n+1] += ct_len3_freq[n];
X }
X ct_dst2_freq[63] += ct_dst3_freq[63];
X ct_len2_freq[63] += ct_len3_freq[63];
X
X /*
X * Construct the code trees and see how much space each will save.
X *
X * It is conceivable that a tree could result in a negative savings
X * if its compressed form is sufficiently long.
X *
X * We need to construct the ZIP-file compressed representation of
X * each tree in order to figure out how much space it will take.
X * However, we don't save these tree representations now; rather,
X * we'll wait until later and reconstruct the representations for
X * whichever two (or three) trees we really need for the output.
X */
X#ifdef IMPDEBUG
X treename = (char *)NULL;
X#endif /* IMPDEBUG */
X
X /* literal code tree */
X retcode = ct_loadf (ct_litc_tree, ct_litc_freq);
X if (retcode != IM_OK) return retcode;
X retcode = ct_gencodes (ct_litc_tree, 1, 16, &ct_litc_saved);
X if (retcode != IM_OK) return retcode;
X retcode = ct_ziprep (ct_litc_tree, &c);
X if (retcode != IM_OK) return retcode;
X ct_litc_saved -= (int) (c[0]+2) * 8;
X
X /* length code tree (2) */
X retcode = ct_loadf (ct_len2_tree, ct_len2_freq);
X if (retcode != IM_OK) return retcode;
X retcode = ct_gencodes (ct_len2_tree, 1, 16, &ct_len2_saved);
X if (retcode != IM_OK) return retcode;
X retcode = ct_ziprep (ct_len2_tree, &c);
X if (retcode != IM_OK) return retcode;
X ct_len2_saved -= (int) (c[0]+2) * 8;
X
X /* length code tree (3) */
X retcode = ct_loadf (ct_len3_tree, ct_len3_freq);
X if (retcode != IM_OK) return retcode;
X retcode = ct_gencodes (ct_len3_tree, 1, 16, &ct_len3_saved);
X if (retcode != IM_OK) return retcode;
X retcode = ct_ziprep (ct_len3_tree, &c);
X if (retcode != IM_OK) return retcode;
X ct_len3_saved -= (int) (c[0]+2) * 8;
X
X /* distance code tree (2) */
X retcode = ct_loadf (ct_dst2_tree, ct_dst2_freq);
X if (retcode != IM_OK) return retcode;
X retcode = ct_gencodes (ct_dst2_tree, 1, 8, &ct_dst2_saved);
X if (retcode != IM_OK) return retcode;
X retcode = ct_ziprep (ct_dst2_tree, &c);
X if (retcode != IM_OK) return retcode;
X ct_dst2_saved -= (int) (c[0]+2) * 8;
X
X /* distance code tree (3) */
X retcode = ct_loadf (ct_dst3_tree, ct_dst3_freq);
X if (retcode != IM_OK) return retcode;
X retcode = ct_gencodes (ct_dst3_tree, 1, 8, &ct_dst3_saved);
X if (retcode != IM_OK) return retcode;
X retcode = ct_ziprep (ct_dst3_tree, &c);
X if (retcode != IM_OK) return retcode;
X ct_dst3_saved -= (int) (c[0]+2) * 8;
X
X /*
X * Determine how big the compressed file will be
X * with, and without, a literal character tree.
X */
X
X /* compressed length (no literal tree) */
X sum = ct_litc_num + ct_lit2_num + ct_strg_num; /* initial bit */
X sum += ct_litc_num * 8; /* literal bytes */
X sum += (ct_lit2_num+ct_strg_num) * 6 - ct_len2_saved; /* lengths */
X sum += 8 * ct_len2_freq[63]; /* oversize lengths */
X sum += (ct_lit2_num+ct_strg_num) * (fd.fd_nbits+6)
X - ct_dst2_saved; /* distances */
X len2 = (sum+7) / 8; /* convert to bytes */
X
X /* compressed length (with literal tree) */
X sum = ct_litc_num + 2*ct_lit2_num + ct_strg_num; /* initial bit */
X sum += (ct_litc_num+2*ct_lit2_num)*8 - ct_litc_saved;/* lit bytes */
X sum += ct_strg_num * 6 - ct_len3_saved; /* lengths */
X sum += 8 * ct_len3_freq[63]; /* oversize lengths */
X sum += ct_strg_num * (fd.fd_nbits+6) - ct_dst3_saved; /* dist's */
X len3 = (sum+7) / 8; /* convert to bytes */
X
X /*
X * PKUNZIP 1.10 requires that the source value 255 in a "literal"
X * tree must be represented by a bit string of length >= 10. The
X * literal tree was already adjusted to ensure that the value 255
X * was given a bit string of length 10 or greater if possible. If
X * this did not succeed -- which would only happen if the longest
X * bit string in the literal tree were of length 8 or 9 -- then the
X * literal tree cannot be used. In such a case, not much would be
X * gained by using it anyway, so there's little reason to be upset.
X */
X if (ct_table[ct_litc_tree].ct_array[255].ct_len < 10)
X len3 = len2;
X
X /*
X * Choose the method of compression which will use the least space
X * for this particular file. The possibilities are: use a literal
X * character tree; or, don't use a literal character tree.
X */
X if (len2 <= len3)
X { fd.fd_method = NO_LITERAL_TREE;
X fd.fd_clen = len2;
X lit_tree = -1;
X len_tree = ct_len2_tree;
X dst_tree = ct_dst2_tree;
X retcode = ct_free (ct_litc_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_free (ct_dst3_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_free (ct_len3_tree);
X if (retcode != IM_OK) return retcode;
X }
X else
X { fd.fd_method = LITERAL_TREE;
X fd.fd_clen = len3;
X lit_tree = ct_litc_tree;
X len_tree = ct_len3_tree;
X dst_tree = ct_dst3_tree;
X retcode = ct_free (ct_dst2_tree);
X if (retcode != IM_OK) return retcode;
X retcode = ct_free (ct_len2_tree);
X if (retcode != IM_OK) return retcode;
X }
X
X /* That's all. */
X return IM_OK;
X}
X
X
X/***********************************************************************
X *
X * Output the code trees.
X */
X
XImpErr
Xct_wrtrees (outfp)
X FILE *outfp; /* output file */
X{ ImpErr retcode;
X U_CHAR *c;
X
X /* Output the literal tree, if any. */
X#ifdef IMPDEBUG
X treename = "Literal";
X#endif /* IMPDEBUG */
X if (lit_tree >= 0)
X { retcode = ct_ziprep (lit_tree, &c);
X if (retcode != IM_OK) return retcode;
X if (zfwrite ((char *) c, (int) (c[0]+2), 1, outfp) != 1)
X return IM_IOERR;
X }
X
X /* Output the length tree. */
X#ifdef IMPDEBUG
X treename = "Length";
X#endif /* IMPDEBUG */
X retcode = ct_ziprep (len_tree, &c);
X if (retcode != IM_OK) return retcode;
X if (zfwrite ((char *) c, (int) (c[0]+2), 1, outfp) != 1)
X return IM_IOERR;
X
X /* Output the distance tree. */
X#ifdef IMPDEBUG
X treename = "Distance";
X#endif /* IMPDEBUG */
X retcode = ct_ziprep (dst_tree, &c);
X if (retcode != IM_OK) return retcode;
X if (zfwrite ((char *) c, (int) (c[0]+2), 1, outfp) != 1)
X return IM_IOERR;
X
X return IM_OK;
X}
X
X/* Macros for outputting bit string. */
X
X#define OUTBITS(value,length) \
X { retcode = bi_rlout ((int) (value), (int) (length)); \
X if (retcode != IM_OK) return retcode; \
X }
X#define OUTCODE(value,tree) \
X { ct_lookup (tree, value, bitstring, bitlength); \
X retcode = bi_rlout (bitstring, bitlength); \
X if (retcode != IM_OK) return retcode; \
X }
X
X/***********************************************************************
X *
X * Output the body of the file in imploded form.
X */
XImpErr
Xct_wrdata (outfp)
X FILE *outfp; /* output (ZIP) file */
X{ MATCH *ma;
X ImpErr retcode;
X register int minmatch;
X int bitstring, bitlength;
X int bitmask = (1 << (fd.fd_nbits+1))-1;
X /* Used to select the bottom 6 or 7 bits of a distance, which are
X * output literally, plus 1 bit marking a distance
X */
X int matches;
X#ifdef IMPDEBUG
X long srcpos;
X#endif /* IMPDEBUG */
X
X /* Determine the minimum match length. */
X minmatch = (lit_tree >= 0) ? 3 : 2;
X
X /* Prepare the I/O. */
X if (tflush (fd.fd_temp) != 0) return IM_IOERR;
X trewind (fd.fd_temp);
X retcode = bi_init (outfp);
X if (retcode != IM_OK) return retcode;
X
X#ifdef IMPDEBUG
X srcpos = 0;
X fprintf (stderr, "\nImploded output:\n");
X#endif /* IMPDEBUG */
X
X /* Read and process data from the temporary file. */
X while ((matches =
X tread ((char *) ma_buf, sizeof(MATCH), MA_BUFSIZE, fd.fd_temp)) > 0)
X for (ma = ma_buf; matches > 0; ma++, matches--)
X {
X int dist = ma->ma_dist;
X int len = 0;
X
X#ifdef IMPDEBUG
X fprintf (stderr, "%8ld: ", srcpos);
X#endif /* IMPDEBUG */
X
X if (dist < 0) {
X dist = -dist, len = 2;
X } else if (dist > 0) {
X len = ma->l.ma_length;
X }
X
X /* Output distance and length if enough characters match. */
X if (len >= minmatch)
X { /* "matched string" header bit (0) */
X#ifdef IMPDEBUG
X fprintf (stderr, "str (dst=%d,len=%d) ",
X dist, len);
X srcpos += len;
X#endif /* IMPDEBUG */
X
X /* ouput one zero bit then the distance */
X dist--;
X OUTBITS ((dist << 1) & bitmask, fd.fd_nbits + 1);
X OUTCODE (dist >> fd.fd_nbits, dst_tree);
X
X /* length -- depends on how it compares to maximum */
X len -= minmatch;
X if (len >= 63)
X { /* big length -- output code for 63, then surplus */
X OUTCODE (63, len_tree);
X OUTBITS ((len - 63), 8);
X }
X else
X { /* small length -- output code */
X OUTCODE (len, len_tree);
X } }
X else if (lit_tree >= 0)
X { /* first or single literal -- header bit (1) plus char */
X#ifdef IMPDEBUG
X fprintf (stderr, "lit (val=%02x) ",
X ma->l.ma_litc[0] & 0xff);
X srcpos++;
X#endif /* IMPDEBUG */
X OUTBITS (1, 1);
X OUTCODE (ma->l.ma_litc[0], lit_tree);
X if (len == 2)
X { /* second literal -- header bit (1) plus char */
X#ifdef IMPDEBUG
X fprintf (stderr, "\n%8ld: lit (val=%02x) ",
X srcpos, ma->l.ma_litc[1] & 0xff);
X srcpos++;
X#endif /* IMPDEBUG */
X OUTBITS (1, 1);
X OUTCODE (ma->l.ma_litc[1], lit_tree);
X } }
X else
X { /* single literal -- header bit (1) plus char */
X#ifdef IMPDEBUG
X fprintf (stderr, "lit (val=%02x) ",
X ma->l.ma_litc[0] & 0xff);
X srcpos++;
X#endif /* IMPDEBUG */
X OUTBITS ((ma->l.ma_litc[0] << 1) + 1, 9);
X }
X#ifdef IMPDEBUG
X putc ('\n', stderr);
X#endif /* IMPDEBUG */
X }
X
X /* Make sure we hit EOF on input without an error. */
X if (terror (fd.fd_temp)
X#ifndef MINIX
X#ifndef __TURBOC__ /* TurboC 2.0 does not set the EOF flag (?) */
X || !teof (fd.fd_temp)
X#endif /* !__TURBOC__ */
X#endif /* !MINIX */
X )
X return IM_IOERR;
X retcode = bi_windup ();
X if (retcode != IM_OK) return retcode;
X
X /* That's all. */
X return IM_OK;
X}
X
X#undef OUTBITS
X#undef OUTCODE
X
X
X/***********************************************************************
X *
X * Deallocate all code trees.
X */
X
XImpErr
Xct_windup ()
X{ int n;
X static windup_already_called = 0;
X ImpErr retcode;
X
X if (windup_already_called)
X { /* Discard any old code trees. */
X for (n = 0; n < MAXTREES; n++)
X { if (ct_table[n].ct_array != NULL)
X { retcode = ct_free (n);
X if (retcode != IM_OK) return retcode;
X } } }
X else
X { /* Initialize the list of active code trees. */
X for (n = 0; n < MAXTREES; n++)
X { ct_table[n].ct_array = NULL;
X ct_table[n].ct_size = 0;
X }
X windup_already_called = 1;
X }
X
X /* That's all. */
X return IM_OK;
X}
X
X
X/**********************************************************************/
END_OF_FILE
if test 45523 -ne `wc -c <'im_ctree.c'`; then
echo shar: \"'im_ctree.c'\" unpacked with wrong size!
fi
# end of 'im_ctree.c'
fi
if test -f 'makevms.com' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'makevms.com'\"
else
echo shar: Extracting \"'makevms.com'\" \(2470 characters\)
sed "s/^X//" >'makevms.com' <<'END_OF_FILE'
X$ !
X$ ! "Makefile" for VMS versions of Zip, ZipNote,
X$ ! ZipSplit, Ship and UnShip (stolen from Unzip)
X$ !
X$ set verify ! like "echo on", eh?
X$ !
X$ !------------------------------- Zip section --------------------------------
X$ !
X$ cc /def=EXPORT zip,zipfile,zipup,fileio,util,tempf,shrink,globals,implode,im_lmat,im_ctree,im_bits
X$ link zip,zipfile,zipup,fileio,util,tempf,shrink,globals,implode,im_lmat,im_ctree,im_bits,sys$input:/opt
Xsys$share:vaxcrtl.exe/shareable
X$ !
X$ ! If you have problems with implode, compile with /define=noimplode
X$ ! and remove all the im* files from the above lines.
X$ !
X$ !-------------------------- Zip utilities section ---------------------------
X$ !
X$ ren zipfile.c zipfile_.c;*
X$ ren zipup.c zipup_.c;*
X$ ren fileio.c fileio_.c;*
X$ ren util.c util_.c;*
X$ cc /def=EXPORT zipnote, zipsplit
X$ cc /def=EXPORT /def=UTIL zipfile_, zipup_, fileio_, util_
X$ ren zipfile_.c zipfile.c;*
X$ ren zipup_.c zipup.c;*
X$ ren fileio_.c fileio.c;*
X$ ren util_.c util.c;*
X$ link zipnote, zipfile_, zipup_, fileio_, globals, sys$input:/opt
Xsys$share:vaxcrtl.exe/shareable
X$ link zipsplit, zipfile_, zipup_, fileio_, globals, sys$input:/opt
Xsys$share:vaxcrtl.exe/shareable
X$ !
X$ !--------------------------- Ship/UnShip section ----------------------------
X$ !
X$ cc ship
X$ link ship,sys$input:/opt
Xsys$share:vaxcrtl.exe/shareable
X$ !
X$ ! Create a hard link. (To remove both files, delete the copy FIRST, then
X$ ! the original. Otherwise, if original deleted first [copy says "no such
X$ ! file"], must use "set file/remove unship.exe;#" to get rid of the copy.
X$ ! Unlike in Unix, deleting the original ALWAYS destroys the data--but not
X$ ! the directory entry of the copy.) Using a hard link saves disk space, by
X$ ! the way. Note, however, that copying a hard link copies the data, not
X$ ! just the link. Therefore, set up the link in the directory in which the
X$ ! executable is to reside, or else rename (move) the executables into the
X$ ! directory.
X$ !
X$ set file/enter=unship.exe ship.exe
X$ !
X$ !----------------------------- Symbols section ------------------------------
X$ !
X$ ! Set up symbols for the various executables. Edit the example below,
X$ ! changing "pc" to "disk:[directory]" as appropriate, and uncomment
X$ ! (remove the exclamation marks).
X$ !
X$ ! zip == "$pc:zip.exe"
X$ ! zipnote == "$pc:zipnote.exe"
X$ ! zipsplit == "$pc:zipsplit.exe"
X$ ! ship == "$pc:ship.exe"
X$ ! unship == "$pc:unship.exe"
X$ !
X$ set noverify
END_OF_FILE
if test 2470 -ne `wc -c <'makevms.com'`; then
echo shar: \"'makevms.com'\" unpacked with wrong size!
fi
# end of 'makevms.com'
fi
echo shar: End of archive 1 \(of 9\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.