| /**************************************************************************** |
| * libs/libc/misc/lib_ncompress.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /* This is the file compress24.c extracted from the ncompress-4.2.4 release |
| * and adapted for NuttX. The original code was released into the public |
| * domain. The original authors are listed below: |
| * |
| * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) |
| * Jim McKie (decvax!mcvax!jim) |
| * Steve Davies (decvax!vax135!petsd!peora!srd) |
| * Ken Turkowski (decvax!decwrl!turtlevax!ken) |
| * James A. Woods (decvax!ihnp4!ames!jaw) |
| * Joe Orost (decvax!vax135!petsd!joe) |
| * Dave Mack (csu@alembic.acs.com) |
| * Peter Jannesen, Network Communication Systems |
| * (peter@ncs.nl) |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <dirent.h> |
| #include <ctype.h> |
| #include <signal.h> |
| #include <errno.h> |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #define RECURSIVE 1 |
| |
| #ifdef __STDC__ |
| # define ARGS(a) a |
| #else |
| # define ARGS(a) () |
| #endif |
| |
| #define LARGS(a) () /* Relay on include files for library func defs. |
| */ |
| |
| #ifndef SIG_TYPE |
| # define SIG_TYPE void (*)() |
| #endif |
| |
| #define MARK(a) { asm(" .globl M.a"); asm("M.a:"); } |
| |
| #ifndef IBUFSIZ |
| # define IBUFSIZ BUFSIZ /* Defailt input buffer size */ |
| #endif |
| #ifndef OBUFSIZ |
| # define OBUFSIZ BUFSIZ /* Default output buffer size */ |
| #endif |
| |
| #define MAXPATHLEN 1024 /* MAXPATHLEN - maximum length of a pathname we |
| * allow */ |
| #define SIZE_INNER_LOOP 256 /* Size of the inter (fast) compress loop */ |
| |
| /* Defines for third byte of header */ |
| #define MAGIC_1 (char_type)'\037' /* First byte of compressed file */ |
| #define MAGIC_2 (char_type)'\235' /* Second byte of compressed file */ |
| |
| #define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ |
| /* Masks 0x20 and 0x40 are free. */ |
| /* I think 0x20 should mean that there is */ |
| /* a fourth header byte (for expansion). */ |
| |
| #define BLOCK_MODE 0x80 /* Block compression if table is full and */ |
| /* compression rate is dropping flush tables */ |
| |
| /* the next two codes should not be changed lightly, as they must not |
| * lie within the contiguous general code space. |
| */ |
| #define FIRST 257 /* first free entry */ |
| #define CLEAR 256 /* table clear output code */ |
| |
| #define INIT_BITS 9 /* initial number of bits/code */ |
| |
| #ifndef SACREDMEM |
| |
| /* SACREDMEM is the amount of physical memory saved for others; compress |
| * will hog the rest. |
| */ |
| # define SACREDMEM 0 |
| #endif |
| |
| #ifndef USERMEM |
| |
| /* Set USERMEM to the maximum amount of physical user memory available |
| * in bytes. USERMEM is used to determine the maximum BITS that can be used |
| * for compression. |
| */ |
| # define USERMEM 450000 /* default user memory */ |
| #endif |
| |
| #ifndef BYTEORDER |
| # define BYTEORDER 0000 |
| #endif |
| |
| #ifndef NOALLIGN |
| # define NOALLIGN 0 |
| #endif |
| |
| /* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ |
| |
| #ifdef interdata /* Perkin-Elmer */ |
| # define SIGNED_COMPARE_SLOW /* signed compare is slower than unsigned */ |
| #endif |
| |
| #ifdef pdp11 /* PDP11: don't forget to compile with -i */ |
| # define BITS 12 /* max bits/code for 16-bit machine */ |
| # define NO_UCHAR /* also if "unsigned char" functions as signed |
| * char */ |
| #endif /* pdp11 */ |
| |
| #ifdef z8000 /* Z8000: */ |
| # define BITS 12 /* 16-bits processor max 12 bits */ |
| # undef vax /* weird preprocessor */ |
| #endif /* z8000 */ |
| |
| #ifdef DOS /* PC/XT/AT (8088) processor */ |
| # define BITS 16 /* 16-bits processor max 12 bits */ |
| # if BITS == 16 |
| # define MAXSEG_64K |
| # endif |
| # undef BYTEORDER |
| # define BYTEORDER 4321 |
| # undef NOALLIGN |
| # define NOALLIGN 1 |
| #endif /* DOS */ |
| |
| #ifdef M_XENIX /* Stupid compiler can't handle arrays with */ |
| # if BITS == 16 /* more than 65535 bytes - so we fake it */ |
| # define MAXSEG_64K |
| # else |
| # if BITS > 13 /* Code only handles BITS = 12, 13, or 16 */ |
| # define BITS 13 |
| # endif |
| # endif |
| #endif |
| |
| #ifndef BITS /* General processor calculate BITS */ |
| # if USERMEM >= (800000+SACREDMEM) |
| # define FAST |
| # else |
| # if USERMEM >= (433484+SACREDMEM) |
| # define BITS 16 |
| # else |
| # if USERMEM >= (229600+SACREDMEM) |
| # define BITS 15 |
| # else |
| # if USERMEM >= (127536+SACREDMEM) |
| # define BITS 14 |
| # else |
| # if USERMEM >= (73464+SACREDMEM) |
| # define BITS 13 |
| # else |
| # define BITS 12 |
| # endif |
| # endif |
| # endif |
| # endif |
| # endif |
| #endif /* BITS */ |
| |
| #ifdef FAST |
| # define HBITS 17 /* 50% occupancy */ |
| # define HSIZE (1<<HBITS) |
| # define HMASK (HSIZE-1) |
| # define HPRIME 9941 |
| # define BITS 16 |
| # undef MAXSEG_64K |
| #else |
| # if BITS == 16 |
| # define HSIZE 69001 /* 95% occupancy */ |
| # endif |
| # if BITS == 15 |
| # define HSIZE 35023 /* 94% occupancy */ |
| # endif |
| # if BITS == 14 |
| # define HSIZE 18013 /* 91% occupancy */ |
| # endif |
| # if BITS == 13 |
| # define HSIZE 9001 /* 91% occupancy */ |
| # endif |
| # if BITS <= 12 |
| # define HSIZE 5003 /* 80% occupancy */ |
| # endif |
| #endif |
| |
| #define CHECK_GAP 10000 |
| |
| typedef long int code_int; |
| |
| #ifdef SIGNED_COMPARE_SLOW |
| typedef unsigned long int count_int; |
| typedef unsigned short int count_short; |
| typedef unsigned long int cmp_code_int; /* Cast to make compare faster */ |
| #else |
| typedef long int count_int; |
| typedef long int cmp_code_int; |
| #endif |
| |
| typedef unsigned char char_type; |
| |
| #define ARGVAL() (*++(*argv) || (--argc && *++argv)) |
| |
| #define MAXCODE(n) (1L << (n)) |
| |
| union bytes |
| { |
| long word; |
| struct |
| { |
| #if BYTEORDER == 4321 |
| char_type b1; |
| char_type b2; |
| char_type b3; |
| char_type b4; |
| #else |
| # if BYTEORDER == 1234 |
| char_type b4; |
| char_type b3; |
| char_type b2; |
| char_type b1; |
| # else |
| # undef BYTEORDER |
| int dummy; |
| # endif |
| #endif |
| } bytes; |
| }; |
| #if BYTEORDER == 4321 && NOALLIGN == 1 |
| # define output(b,o,c,n) { \ |
| *(long *)&((b)[(o)>>3]) |= ((long)(c))<<((o)&0x7);\ |
| (o) += (n); \ |
| } |
| #else |
| # ifdef BYTEORDER |
| # define output(b,o,c,n) { char_type *p = &(b)[(o)>>3]; \ |
| union bytes i; \ |
| i.word = ((long)(c))<<((o)&0x7); \ |
| p[0] |= i.bytes.b1; \ |
| p[1] |= i.bytes.b2; \ |
| p[2] |= i.bytes.b3; \ |
| (o) += (n); \ |
| } |
| # else |
| # define output(b,o,c,n) { char_type *p = &(b)[(o)>>3]; \ |
| long i = ((long)(c))<<((o)&0x7); \ |
| p[0] |= (char_type)(i); \ |
| p[1] |= (char_type)(i>>8); \ |
| p[2] |= (char_type)(i>>16); \ |
| (o) += (n); \ |
| } |
| # endif |
| #endif |
| #if BYTEORDER == 4321 && NOALLIGN == 1 |
| # define input(b,o,c,n,m){ \ |
| (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m); \ |
| (o) += (n); \ |
| } |
| #else |
| # define input(b,o,c,n,m){ char_type *p = &(b)[(o)>>3]; \ |
| (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \ |
| ((long)(p[2])<<16))>>((o)&0x7))&(m); \ |
| (o) += (n); \ |
| } |
| #endif |
| |
| char *progname; /* Program name */ |
| int silent = 0; /* don't tell me about errors */ |
| int quiet = 1; /* don't tell me about compression */ |
| int do_decomp = 0; /* Decompress mode */ |
| int force = 0; /* Force overwrite of files and links */ |
| int nomagic = 0; /* Use a 3-byte magic number header, */ |
| |
| /* unless old file */ |
| |
| int block_mode = BLOCK_MODE; /* Block compress mode -C compatible with 2.0 */ |
| int maxbits = BITS; /* user settable max # bits/code */ |
| int zcat_flg = 0; /* Write output on stdout, suppress messages */ |
| int recursive = 0; /* compress directories */ |
| int exit_code = -1; /* Exitcode of compress (-1 no file compressed) */ |
| |
| char_type inbuf[IBUFSIZ + 64]; /* Input buffer */ |
| char_type outbuf[OBUFSIZ + 2048]; /* Output buffer */ |
| |
| struct stat infstat; /* Input file status */ |
| char *ifname; /* Input filename */ |
| int remove_ofname = 0; /* Remove output file on a error */ |
| char ofname[MAXPATHLEN]; /* Output filename */ |
| int fgnd_flag = 0; /* Running in background (SIGINT=SIGIGN) */ |
| |
| long bytes_in; /* Total number of byte from input */ |
| long bytes_out; /* Total number of byte to output */ |
| |
| /* To save much memory, we overlay the table used by compress() with those |
| * used by decompress(). The tab_prefix table is the same size and type |
| * as the codetab. The tab_suffix table needs 2**BITS characters. We |
| * get this from the beginning of htab. The output stack uses the rest |
| * of htab, and contains characters. There is plenty of room for any |
| * possible stack (stack used to be 8000 characters). |
| */ |
| #ifdef MAXSEG_64K |
| count_int htab0[8192]; |
| count_int htab1[8192]; |
| count_int htab2[8192]; |
| count_int htab3[8192]; |
| count_int htab4[8192]; |
| count_int htab5[8192]; |
| count_int htab6[8192]; |
| count_int htab7[8192]; |
| count_int htab8[HSIZE - 65536]; |
| count_int *htab[9] = |
| { |
| htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 |
| }; |
| |
| unsigned short code0tab[16384]; |
| unsigned short code1tab[16384]; |
| unsigned short code2tab[16384]; |
| unsigned short code3tab[16384]; |
| unsigned short code4tab[16384]; |
| unsigned short *codetab[5] = |
| { |
| code0tab, code1tab, code2tab, code3tab, code4tab |
| }; |
| |
| # define htabof(i) (htab[(i) >> 13][(i) & 0x1fff]) |
| # define codetabof(i) (codetab[(i) >> 14][(i) & 0x3fff]) |
| # define tab_prefixof(i) codetabof(i) |
| # define tab_suffixof(i) ((char_type *)htab[(i)>>15])[(i) & 0x7fff] |
| # define de_stack ((char_type *)(&htab2[8191])) |
| void clear_htab() |
| { |
| memset(htab0, -1, sizeof(htab0)); |
| memset(htab1, -1, sizeof(htab1)); |
| memset(htab2, -1, sizeof(htab2)); |
| memset(htab3, -1, sizeof(htab3)); |
| memset(htab4, -1, sizeof(htab4)); |
| memset(htab5, -1, sizeof(htab5)); |
| memset(htab6, -1, sizeof(htab6)); |
| memset(htab7, -1, sizeof(htab7)); |
| memset(htab8, -1, sizeof(htab8)); |
| } |
| |
| # define clear_tab_prefixof() memset(code0tab, 0, 256); |
| #else /* Normal machine */ |
| count_int htab[HSIZE]; |
| unsigned short codetab[HSIZE]; |
| |
| # define htabof(i) htab[i] |
| # define codetabof(i) codetab[i] |
| # define tab_prefixof(i) codetabof(i) |
| # define tab_suffixof(i) ((char_type *)(htab))[i] |
| # define de_stack ((char_type *)&(htab[HSIZE-1])) |
| # define clear_htab() memset(htab, -1, sizeof(htab)) |
| # define clear_tab_prefixof() memset(codetab, 0, 256); |
| |
| # ifdef FAST |
| int primetab[256] = /* Special secudary hash table. */ |
| { |
| 1013, -1061, 1109, -1181, 1231, -1291, 1361, -1429, |
| 1481, -1531, 1583, -1627, 1699, -1759, 1831, -1889, |
| 1973, -2017, 2083, -2137, 2213, -2273, 2339, -2383, |
| 2441, -2531, 2593, -2663, 2707, -2753, 2819, -2887, |
| 2957, -3023, 3089, -3181, 3251, -3313, 3361, -3449, |
| 3511, -3557, 3617, -3677, 3739, -3821, 3881, -3931, |
| 4013, -4079, 4139, -4219, 4271, -4349, 4423, -4493, |
| 4561, -4639, 4691, -4783, 4831, -4931, 4973, -5023, |
| 5101, -5179, 5261, -5333, 5413, -5471, 5521, -5591, |
| 5659, -5737, 5807, -5857, 5923, -6029, 6089, -6151, |
| 6221, -6287, 6343, -6397, 6491, -6571, 6659, -6709, |
| 6791, -6857, 6917, -6983, 7043, -7129, 7213, -7297, |
| 7369, -7477, 7529, -7577, 7643, -7703, 7789, -7873, |
| 7933, -8017, 8093, -8171, 8237, -8297, 8387, -8461, |
| 8543, -8627, 8689, -8741, 8819, -8867, 8963, -9029, |
| 9109, -9181, 9241, -9323, 9397, -9439, 9511, -9613, |
| 9677, -9743, 9811, -9871, 9941, -10061, 10111, -10177, |
| 10259, -10321, 10399, -10477, 10567, -10639, 10711, -10789, |
| 10867, -10949, 11047, -11113, 11173, -11261, 11329, -11423, |
| 11491, -11587, 11681, -11777, 11827, -11903, 11959, -12041, |
| 12109, -12197, 12263, -12343, 12413, -12487, 12541, -12611, |
| 12671, -12757, 12829, -12917, 12979, -13043, 13127, -13187, |
| 13291, -13367, 13451, -13523, 13619, -13691, 13751, -13829, |
| 13901, -13967, 14057, -14153, 14249, -14341, 14419, -14489, |
| 14557, -14633, 14717, -14767, 14831, -14897, 14983, -15083, |
| 15149, -15233, 15289, -15359, 15427, -15497, 15583, -15649, |
| 15733, -15791, 15881, -15937, 16057, -16097, 16189, -16267, |
| 16363, -16447, 16529, -16619, 16691, -16763, 16879, -16937, |
| 17021, -17093, 17183, -17257, 17341, -17401, 17477, -17551, |
| 17623, -17713, 17791, -17891, 17957, -18041, 18097, -18169, |
| 18233, -18307, 18379, -18451, 18523, -18637, 18731, -18803, |
| 18919, -19031, 19121, -19211, 19273, -19381, 19429, -19477 |
| }; |
| # endif |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /* compress fdin to fdout |
| * |
| * Algorithm: use open addressing double hashing (no chaining) on the |
| * prefix code / next character combination. We do a variant of Knuth's |
| * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime |
| * secondary probe. Here, the modular division first probe is gives way |
| * to a faster exclusive-or manipulation. Also do block compression with |
| * an adaptive reset, whereby the code table is cleared when the compression |
| * ratio decreases, but after the table fills. The variable-length output |
| * codes are re-sized at this point, and a special CLEAR code is generated |
| * for the decompressor. Late addition: construct the table according to |
| * file size for noticeable speed improvement on small files. Please direct |
| * questions about this implementation to ames!jaw. |
| */ |
| |
| void compress(int fdin, int fdout) |
| { |
| long hp; |
| int rpos; |
| long fc; |
| int outbits; |
| int rlop; |
| int rsize; |
| int stcode; |
| code_int free_ent; |
| int boff; |
| int n_bits; |
| int ratio; |
| long checkpoint; |
| code_int extcode; |
| union |
| { |
| long code; |
| struct |
| { |
| char_type c; |
| unsigned short ent; |
| } e; |
| } fcode; |
| |
| ratio = 0; |
| checkpoint = CHECK_GAP; |
| extcode = MAXCODE(n_bits = INIT_BITS) + 1; |
| stcode = 1; |
| free_ent = FIRST; |
| |
| memset(outbuf, 0, sizeof(outbuf)); |
| bytes_out = 0; |
| bytes_in = 0; |
| outbuf[0] = MAGIC_1; |
| outbuf[1] = MAGIC_2; |
| outbuf[2] = (char)(maxbits | block_mode); |
| boff = outbits = (3 << 3); |
| fcode.code = 0; |
| |
| clear_htab(); |
| |
| while ((rsize = read(fdin, inbuf, IBUFSIZ)) > 0) |
| { |
| if (bytes_in == 0) |
| { |
| fcode.e.ent = inbuf[0]; |
| rpos = 1; |
| } |
| else |
| rpos = 0; |
| |
| rlop = 0; |
| |
| do |
| { |
| if (free_ent >= extcode && fcode.e.ent < FIRST) |
| { |
| if (n_bits < maxbits) |
| { |
| boff = outbits = (outbits - 1) + ((n_bits << 3) - |
| ((outbits - boff - 1 + |
| (n_bits << 3)) % |
| (n_bits << 3))); |
| if (++n_bits < maxbits) |
| extcode = MAXCODE(n_bits) + 1; |
| else |
| extcode = MAXCODE(n_bits); |
| } |
| else |
| { |
| extcode = MAXCODE(16) + OBUFSIZ; |
| stcode = 0; |
| } |
| } |
| |
| if (!stcode && bytes_in >= checkpoint && fcode.e.ent < FIRST) |
| { |
| long int rat; |
| |
| checkpoint = bytes_in + CHECK_GAP; |
| |
| if (bytes_in > 0x007fffff) |
| { |
| /* shift will overflow */ |
| |
| rat = (bytes_out + (outbits >> 3)) >> 8; |
| |
| if (rat == 0) /* Don't divide by zero */ |
| rat = 0x7fffffff; |
| else |
| rat = bytes_in / rat; |
| } |
| else |
| |
| /* 8 fractional bits */ |
| |
| rat = (bytes_in << 8) / (bytes_out + (outbits >> 3)); |
| |
| if (rat >= ratio) |
| ratio = (int)rat; |
| else |
| { |
| ratio = 0; |
| clear_htab(); |
| output(outbuf, outbits, CLEAR, n_bits); |
| boff = outbits = (outbits - 1) + ((n_bits << 3) - |
| ((outbits - boff - 1 + |
| (n_bits << 3)) % |
| (n_bits << 3))); |
| extcode = MAXCODE(n_bits = INIT_BITS) + 1; |
| free_ent = FIRST; |
| stcode = 1; |
| } |
| } |
| |
| if (outbits >= (OBUFSIZ << 3)) |
| { |
| if (write(fdout, outbuf, OBUFSIZ) != OBUFSIZ) |
| write_error(); |
| |
| outbits -= (OBUFSIZ << 3); |
| boff = -(((OBUFSIZ << 3) - boff) % (n_bits << 3)); |
| bytes_out += OBUFSIZ; |
| |
| memcpy(outbuf, outbuf + OBUFSIZ, (outbits >> 3) + 1); |
| memset(outbuf + (outbits >> 3) + 1, '\0', OBUFSIZ); |
| } |
| |
| { |
| int i; |
| |
| i = rsize - rlop; |
| |
| if ((code_int) i > extcode - free_ent) |
| i = (int)(extcode - free_ent); |
| if (i > ((sizeof(outbuf) - 32) * 8 - outbits) / n_bits) |
| i = ((sizeof(outbuf) - 32) * 8 - outbits) / n_bits; |
| |
| if (!stcode && (long)i > checkpoint - bytes_in) |
| i = (int)(checkpoint - bytes_in); |
| |
| rlop += i; |
| bytes_in += i; |
| } |
| |
| goto next; |
| hfound:fcode.e.ent = codetabof(hp); |
| next:if (rpos >= rlop) |
| goto endlop; |
| next2:fcode.e.c = inbuf[rpos++]; |
| # ifndef FAST |
| { |
| code_int i; |
| fc = fcode.code; |
| |
| hp = (((long)(fcode.e.c)) << (BITS - 8)) ^ (long)(fcode.e.ent); |
| |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| |
| if (i != -1) |
| { |
| long disp; |
| |
| disp = (HSIZE - hp) - 1; /* secondary hash (after G. |
| * Knott) */ |
| |
| do |
| { |
| if ((hp -= disp) < 0) |
| hp += HSIZE; |
| |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| } |
| while (i != -1); |
| } |
| } |
| # else |
| { |
| long i; |
| long p; |
| fc = fcode.code; |
| |
| hp = ((((long)(fcode.e.c)) << (HBITS - 8)) ^ |
| (long)(fcode.e.ent)); |
| |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| if (i == -1) |
| goto out; |
| |
| p = primetab[fcode.e.c]; |
| lookup:hp = (hp + p) & HMASK; |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| if (i == -1) |
| goto out; |
| hp = (hp + p) & HMASK; |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| if (i == -1) |
| goto out; |
| hp = (hp + p) & HMASK; |
| if ((i = htabof(hp)) == fc) |
| goto hfound; |
| if (i == -1) |
| goto out; |
| goto lookup; |
| } |
| |
| out:; |
| # endif |
| output(outbuf, outbits, fcode.e.ent, n_bits); |
| |
| { |
| long fc = fcode.code; |
| fcode.e.ent = fcode.e.c; |
| |
| if (stcode) |
| { |
| codetabof(hp) = (unsigned short)free_ent++; |
| htabof(hp) = fc; |
| } |
| } |
| |
| goto next; |
| |
| endlop:if (fcode.e.ent >= FIRST && rpos < rsize) |
| goto next2; |
| |
| if (rpos > rlop) |
| { |
| bytes_in += rpos - rlop; |
| rlop = rpos; |
| } |
| } |
| |
| while (rlop < rsize); |
| } |
| |
| if (rsize < 0) |
| read_error(); |
| |
| if (bytes_in > 0) |
| output(outbuf, outbits, fcode.e.ent, n_bits); |
| |
| if (write(fdout, outbuf, (outbits + 7) >> 3) != (outbits + 7) >> 3) |
| write_error(); |
| |
| bytes_out += (outbits + 7) >> 3; |
| } |
| |
| /* Decompress stdin to stdout. This routine adapts to the codes in the |
| * file building the "string" table on-the-fly; requiring no table to |
| * be stored in the compressed file. The tables used herein are shared |
| * with those of the compress() routine. See the definitions above. |
| */ |
| |
| void decompress(int fdin, int fdout) |
| int fdin; |
| int fdout; |
| { |
| char_type *stackp; |
| code_int code; |
| int finchar; |
| code_int oldcode; |
| code_int incode; |
| int inbits; |
| int posbits; |
| int outpos; |
| int insize; |
| int bitmask; |
| code_int free_ent; |
| code_int maxcode; |
| code_int maxmaxcode; |
| int n_bits; |
| int rsize; |
| |
| bytes_in = 0; |
| bytes_out = 0; |
| insize = 0; |
| |
| while (insize < 3 && (rsize = read(fdin, inbuf + insize, IBUFSIZ)) > 0) |
| insize += rsize; |
| |
| if (insize < 3 || inbuf[0] != MAGIC_1 || inbuf[1] != MAGIC_2) |
| { |
| if (rsize < 0) |
| read_error(); |
| |
| if (insize > 0) |
| { |
| fprintf(stderr, "%s: not in compressed format\n", |
| (ifname[0] != '\0' ? ifname : "stdin")); |
| exit_code = 1; |
| } |
| |
| return; |
| } |
| |
| maxbits = inbuf[2] & BIT_MASK; |
| block_mode = inbuf[2] & BLOCK_MODE; |
| |
| if (maxbits > BITS) |
| { |
| fprintf(stderr, |
| "%s: compressed with %d bits, can only handle %d bits\n", |
| (*ifname != '\0' ? ifname : "stdin"), maxbits, BITS); |
| exit_code = 4; |
| return; |
| } |
| |
| maxmaxcode = MAXCODE(maxbits); |
| |
| bytes_in = insize; |
| maxcode = MAXCODE(n_bits = INIT_BITS) - 1; |
| bitmask = (1 << n_bits) - 1; |
| oldcode = -1; |
| finchar = 0; |
| outpos = 0; |
| posbits = 3 << 3; |
| |
| free_ent = ((block_mode) ? FIRST : 256); |
| |
| clear_tab_prefixof(); /* As above, initialize the first 256 entries |
| * in the table. */ |
| |
| for (code = 255; code >= 0; --code) |
| tab_suffixof(code) = (char_type) code; |
| |
| do |
| { |
| resetbuf:; |
| { |
| int i; |
| int e; |
| int o; |
| |
| o = posbits >> 3; |
| e = o <= insize ? insize - o : 0; |
| |
| for (i = 0; i < e; ++i) |
| inbuf[i] = inbuf[i + o]; |
| |
| insize = e; |
| posbits = 0; |
| } |
| |
| if (insize < sizeof(inbuf) - IBUFSIZ) |
| { |
| if ((rsize = read(fdin, inbuf + insize, IBUFSIZ)) < 0) |
| read_error(); |
| |
| insize += rsize; |
| } |
| |
| inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : |
| (insize << 3) - (n_bits - 1)); |
| |
| while (inbits > posbits) |
| { |
| if (free_ent > maxcode) |
| { |
| posbits = ((posbits - 1) + ((n_bits << 3) - |
| (posbits - 1 + |
| (n_bits << 3)) % (n_bits << 3))); |
| |
| ++n_bits; |
| if (n_bits == maxbits) |
| maxcode = maxmaxcode; |
| else |
| maxcode = MAXCODE(n_bits) - 1; |
| |
| bitmask = (1 << n_bits) - 1; |
| goto resetbuf; |
| } |
| |
| input(inbuf, posbits, code, n_bits, bitmask); |
| |
| if (oldcode == -1) |
| { |
| if (code >= 256) |
| { |
| fprintf(stderr, "oldcode:-1 code:%i\n", (int)(code)); |
| fprintf(stderr, "uncompress: corrupt input\n"); |
| abort_compress(); |
| } |
| |
| outbuf[outpos++] = |
| (char_type)(finchar = (int)(oldcode = code)); |
| continue; |
| } |
| |
| if (code == CLEAR && block_mode) |
| { |
| clear_tab_prefixof(); |
| free_ent = FIRST - 1; |
| posbits = ((posbits - 1) + ((n_bits << 3) - |
| (posbits - 1 + |
| (n_bits << 3)) % (n_bits << 3))); |
| maxcode = MAXCODE(n_bits = INIT_BITS) - 1; |
| bitmask = (1 << n_bits) - 1; |
| goto resetbuf; |
| } |
| |
| incode = code; |
| stackp = de_stack; |
| |
| if (code >= free_ent) /* Special case for KwKwK string. */ |
| { |
| if (code > free_ent) |
| { |
| char_type *p; |
| |
| posbits -= n_bits; |
| p = &inbuf[posbits >> 3]; |
| |
| fprintf(stderr, |
| "insize:%d posbits:%d " |
| "inbuf:%02X %02X %02X %02X %02X (%d)\n", |
| insize, posbits, p[1], p[0], p[1], p[2], p[3], |
| (posbits & 07)); |
| fprintf(stderr, "uncompress: corrupt input\n"); |
| abort_compress(); |
| } |
| |
| *--stackp = (char_type) finchar; |
| code = oldcode; |
| } |
| |
| /* Generate output characters in reverse order */ |
| |
| while ((cmp_code_int) code >= (cmp_code_int) 256) |
| { |
| *--stackp = tab_suffixof(code); |
| code = tab_prefixof(code); |
| } |
| |
| *--stackp = (char_type) (finchar = tab_suffixof(code)); |
| |
| /* And put them out in forward order */ |
| |
| { |
| int i; |
| |
| if (outpos + (i = (de_stack - stackp)) >= OBUFSIZ) |
| { |
| do |
| { |
| if (i > OBUFSIZ - outpos) |
| i = OBUFSIZ - outpos; |
| |
| if (i > 0) |
| { |
| memcpy(outbuf + outpos, stackp, i); |
| outpos += i; |
| } |
| |
| if (outpos >= OBUFSIZ) |
| { |
| if (write(fdout, outbuf, outpos) != outpos) |
| write_error(); |
| |
| outpos = 0; |
| } |
| |
| stackp += i; |
| } |
| while ((i = (de_stack - stackp)) > 0); |
| } |
| else |
| { |
| memcpy(outbuf + outpos, stackp, i); |
| outpos += i; |
| } |
| } |
| |
| if ((code = free_ent) < maxmaxcode) /* Generate the new entry. */ |
| { |
| tab_prefixof(code) = (unsigned short)oldcode; |
| tab_suffixof(code) = (char_type) finchar; |
| free_ent = code + 1; |
| } |
| |
| oldcode = incode; /* Remember previous code. */ |
| } |
| |
| bytes_in += rsize; |
| } |
| while (rsize > 0); |
| |
| if (outpos > 0 && write(fdout, outbuf, outpos) != outpos) |
| write_error(); |
| } |
| |
| void read_error() |
| { |
| fprintf(stderr, "\nread error on"); |
| perror((ifname[0] != '\0') ? ifname : "stdin"); |
| abort_compress(); |
| } |
| |
| void write_error() |
| { |
| fprintf(stderr, "\nwrite error on"); |
| perror((ofname[0] != '\0') ? ofname : "stdout"); |
| abort_compress(); |
| } |
| |
| void abort_compress() |
| { |
| if (remove_ofname) |
| unlink(ofname); |
| |
| exit(1); |
| } |
| |
| void prratio(stream, num, den) |
| FILE *stream; |
| long int num; |
| long int den; |
| { |
| int q; |
| |
| if (den > 0) |
| { |
| if (num > 214748L) |
| q = (int)(num / (den / 10000L)); /* 2147483647/10000 */ |
| else |
| q = (int)(10000L * num / den); /* Long calculations, though */ |
| } |
| else |
| q = 10000; |
| |
| if (q < 0) |
| { |
| putc('-', stream); |
| q = -q; |
| } |
| |
| fprintf(stream, "%d.%02d%%", q / 100, q % 100); |
| } |