diff options
Diffstat (limited to 'package/heirloom-cpio/src/unshrink.c')
| -rw-r--r-- | package/heirloom-cpio/src/unshrink.c | 307 | 
1 files changed, 307 insertions, 0 deletions
| diff --git a/package/heirloom-cpio/src/unshrink.c b/package/heirloom-cpio/src/unshrink.c new file mode 100644 index 000000000..61f5c507c --- /dev/null +++ b/package/heirloom-cpio/src/unshrink.c @@ -0,0 +1,307 @@ +/* + * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003. + * + * Derived from unzip 5.40. + * + * Sccsid @(#)unshrink.c	1.4 (gritter) 6/18/04 + */ +/*--------------------------------------------------------------------------- + +  unshrink.c                     version 1.21                     23 Nov 95 + + +       NOTE:  This code may or may not infringe on the so-called "Welch +       patent" owned by Unisys.  (From reading the patent, it appears +       that a pure LZW decompressor is *not* covered, but this claim has +       not been tested in court, and Unisys is reported to believe other- +       wise.)  It is therefore the responsibility of the user to acquire +       whatever license(s) may be required for legal use of this code. + +       THE INFO-ZIP GROUP DISCLAIMS ALL LIABILITY FOR USE OF THIS CODE +       IN VIOLATION OF APPLICABLE PATENT LAW. + + +  Shrinking is basically a dynamic LZW algorithm with allowed code sizes of +  up to 13 bits; in addition, there is provision for partial clearing of +  leaf nodes.  PKWARE uses the special code 256 (decimal) to indicate a +  change in code size or a partial clear of the code tree:  256,1 for the +  former and 256,2 for the latter.  [Note that partial clearing can "orphan" +  nodes:  the parent-to-be can be cleared before its new child is added, +  but the child is added anyway (as an orphan, as though the parent still +  existed).  When the tree fills up to the point where the parent node is +  reused, the orphan is effectively "adopted."  Versions prior to 1.05 were +  affected more due to greater use of pointers (to children and siblings +  as well as parents).] + +  This replacement version of unshrink.c was written from scratch.  It is +  based only on the algorithms described in Mark Nelson's _The Data Compres- +  sion Book_ and in Terry Welch's original paper in the June 1984 issue of +  IEEE _Computer_; no existing source code, including any in Nelson's book, +  was used. + +  Memory requirements have been reduced in this version and are now no more +  than the original Sam Smith code.  This is still larger than any of the +  other algorithms:  at a minimum, 8K+8K+16K (stack+values+parents) assuming +  16-bit short ints, and this does not even include the output buffer (the +  other algorithms leave the uncompressed data in the work area, typically +  called slide[]).  For machines with a 64KB data space this is a problem, +  particularly when text conversion is required and line endings have more +  than one character.  UnZip's solution is to use two roughly equal halves +  of outbuf for the ASCII conversion in such a case; the "unshrink" argument +  to flush() signals that this is the case. + +  For large-memory machines, a second outbuf is allocated for translations, +  but only if unshrinking and only if translations are required. + +              | binary mode  |        text mode +    --------------------------------------------------- +    big mem   |  big outbuf  | big outbuf + big outbuf2  <- malloc'd here +    small mem | small outbuf | half + half small outbuf + +  Copyright 1994, 1995 Greg Roelofs.  See the accompanying file "COPYING" +  in UnZip 5.20 (or later) source or binary distributions. + +  From "COPYING": + +   The following copyright applies to the new version of unshrink.c, +   distributed with UnZip version 5.2 and later: + +     * Copyright (c) 1994 Greg Roelofs. +     * Permission is granted to any individual/institution/corporate +     * entity to use, copy, redistribute or modify this software for +     * any purpose whatsoever, subject to the conditions noted in the +     * Frequently Asked Questions section below, plus one additional +     * condition:  namely, that my name not be removed from the source +     * code.  (Other names may, of course, be added as modifications +     * are made.)  Corporate legal staff (like at IBM :-) ) who have +     * problems understanding this can contact me through Zip-Bugs... + + +   Q. Can I use the source code of Zip and UnZip in my commercial +      application? + +   A. Yes, so long as you include in your product an acknowledgment; a +      pointer to the original, free compression sources; and a statement +      making it clear that there are no extra or hidden charges resulting +      from the use of our compression code in your product (see below for +      an example).  The acknowledgment should appear in at least one piece +      of human-readable documentation (e.g., a README file or man page), +      although additionally putting it in the executable(s) is OK, too. +      In other words, you are allowed to sell only your own work, not ours, +      and we'd like a little credit.  (Note the additional restrictions +      above on the code in unreduce.c, unshrink.c, vms.c, time_lib.c, and +      everything in the wince and windll subdirectories.)  Contact us at +      Zip-Bugs@lists.wku.edu if you have special requirements.  We also +      like to hear when our code is being used, but we don't require that. + +         <Product> incorporates compression code from the Info-ZIP group. +         There are no extra charges or costs due to the use of this code, +         and the original compression sources are freely available from +         http://www.cdrom.com/pub/infozip/ or ftp://ftp.cdrom.com/pub/infozip/ +         on the Internet. + +      If you only need compression capability, not full zipfile support, +      you might want to look at zlib instead; it has fewer restrictions +      on commercial use.  See http://www.cdrom.com/pub/infozip/zlib/ . + +  ---------------------------------------------------------------------------*/ + +#include <string.h> +#include <stdio.h> + +#include "cpio.h" +#include "unzip.h" + +static void	partial_clear(struct globals *); + +#define	trace() + +/* HSIZE is defined as 2^13 (8192) in unzip.h */ +#define	BOGUSCODE  256 +#define	FLAG_BITS  parent        /* upper bits of parent[] used as flag bits */ +#define	CODE_MASK  (HSIZE - 1)   /* 0x1fff (lower bits are parent's index) */ +#define	FREE_CODE  HSIZE         /* 0x2000 (code is unused or was cleared) */ +#define	HAS_CHILD  (HSIZE << 1)  /* 0x4000 (code has a child--do not clear) */ + +#define parent G.area.shrink.Parent +#define Value  G.area.shrink.value /* "value" conflicts with Pyramid ioctl.h */ +#define stack  G.area.shrink.Stack + +/***********************/ +/* Function unshrink() */ +/***********************/ + +int +zipunshrink(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc) +{ +    struct globals G; +    int offset = (HSIZE - 1); +    uint8_t *stacktop = stack + offset; +    register uint8_t *newstr; +    int codesize=9, len, KwKwK; +    int16_t code, oldcode, freecode, curcode; +    int16_t lastfreecode; +    unsigned int outbufsiz; + +/*--------------------------------------------------------------------------- +    Initialize various variables. +  ---------------------------------------------------------------------------*/ + +    memset(&G, 0, sizeof G); +    G.tgt = tgt; +    G.tfd = tfd; +    G.doswap = doswap; +    G.crc = crc; +    G.zsize = G.uzsize = f->f_csize; +    lastfreecode = BOGUSCODE; + +    for (code = 0;  code < BOGUSCODE;  ++code) { +        Value[code] = (uint8_t)code; +        parent[code] = BOGUSCODE; +    } +    for (code = BOGUSCODE+1;  code < HSIZE;  ++code) +        parent[code] = FREE_CODE; + +    outbufsiz = OUTBUFSIZ; +    G.outptr = G.outbuf; +    G.outcnt = 0L; + +/*--------------------------------------------------------------------------- +    Get and output first code, then loop over remaining ones. +  ---------------------------------------------------------------------------*/ + +    READBITS(codesize, oldcode) +    if (!G.zipeof) { +        *G.outptr++ = (uint8_t)oldcode; +        ++G.outcnt; +    } + +    do { +        READBITS(codesize, code) +        if (G.zipeof) +            break; +        if (code == BOGUSCODE) {   /* possible to have consecutive escapes? */ +            READBITS(codesize, code) +            if (code == 1) { +                ++codesize; +                Trace((stderr, " (codesize now %d bits)\n", codesize)); +            } else if (code == 2) { +                Trace((stderr, " (partial clear code)\n")); +                partial_clear(&G);   /* clear leafs (nodes with no children) */ +                Trace((stderr, " (done with partial clear)\n")); +                lastfreecode = BOGUSCODE;  /* reset start of free-node search */ +            } +            continue; +        } + +    /*----------------------------------------------------------------------- +        Translate code:  traverse tree from leaf back to root. +      -----------------------------------------------------------------------*/ + +        newstr = stacktop; +        curcode = code; + +        if (parent[curcode] == FREE_CODE) { +            /* or (FLAG_BITS[curcode] & FREE_CODE)? */ +            KwKwK = TRUE; +            Trace((stderr, " (found a KwKwK code %d; oldcode = %d)\n", code, +              oldcode)); +            --newstr;   /* last character will be same as first character */ +            curcode = oldcode; +        } else +            KwKwK = FALSE; + +        do { +            *newstr-- = Value[curcode]; +            curcode = (int16_t)(parent[curcode] & CODE_MASK); +        } while (curcode != BOGUSCODE); + +        len = (int)(stacktop - newstr++); +        if (KwKwK) +            *stacktop = *newstr; + +    /*----------------------------------------------------------------------- +        Write expanded string in reverse order to output buffer. +      -----------------------------------------------------------------------*/ + +        Trace((stderr, "code %4d; oldcode %4d; char %3d (%c); string [", code, +          oldcode, (int)(*newstr), (*newstr<32 || *newstr>=127)? ' ':*newstr)); + +        { +            register uint8_t *p; + +            for (p = newstr;  p < newstr+len;  ++p) { +                *G.outptr++ = *p; +                if (++G.outcnt == outbufsiz) { +		    flush(&G, G.outbuf, G.outcnt); +                    G.outptr = G.outbuf; +                    G.outcnt = 0L; +                } +            } +        } + +    /*----------------------------------------------------------------------- +        Add new leaf (first character of newstr) to tree as child of oldcode. +      -----------------------------------------------------------------------*/ + +        /* search for freecode */ +        freecode = (int16_t)(lastfreecode + 1); +        /* add if-test before loop for speed? */ +        while (parent[freecode] != FREE_CODE) +            ++freecode; +        lastfreecode = freecode; +        Trace((stderr, "]; newcode %d\n", freecode)); + +        Value[freecode] = *newstr; +        parent[freecode] = oldcode; +        oldcode = code; + +    } while (!G.zipeof); + +/*--------------------------------------------------------------------------- +    Flush any remaining data and return to sender... +  ---------------------------------------------------------------------------*/ + +    if (G.outcnt > 0L) +	    flush(&G, G.outbuf, G.outcnt); + +    return G.status; + +} /* end function unshrink() */ + + + + + +/****************************/ +/* Function partial_clear() */      /* no longer recursive... */ +/****************************/ + +static void +partial_clear(struct globals *Gp) +{ +#define	G	(*Gp) +    register int16_t code; + +    /* clear all nodes which have no children (i.e., leaf nodes only) */ + +    /* first loop:  mark each parent as such */ +    for (code = BOGUSCODE+1;  code < HSIZE;  ++code) { +        register int16_t cparent = (int16_t)(parent[code] & CODE_MASK); + +        if (cparent > BOGUSCODE && cparent != FREE_CODE) +            FLAG_BITS[cparent] |= HAS_CHILD;   /* set parent's child-bit */ +    } + +    /* second loop:  clear all nodes *not* marked as parents; reset flag bits */ +    for (code = BOGUSCODE+1;  code < HSIZE;  ++code) { +        if (FLAG_BITS[code] & HAS_CHILD)    /* just clear child-bit */ +            FLAG_BITS[code] &= ~HAS_CHILD; +        else {                              /* leaf:  lose it */ +            Trace((stderr, "%d\n", code)); +            parent[code] = FREE_CODE; +        } +    } + +    return; +} | 
