unshrink.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
  3. *
  4. * Derived from unzip 5.40.
  5. *
  6. * Sccsid @(#)unshrink.c 1.4 (gritter) 6/18/04
  7. */
  8. /*---------------------------------------------------------------------------
  9. unshrink.c version 1.21 23 Nov 95
  10. NOTE: This code may or may not infringe on the so-called "Welch
  11. patent" owned by Unisys. (From reading the patent, it appears
  12. that a pure LZW decompressor is *not* covered, but this claim has
  13. not been tested in court, and Unisys is reported to believe other-
  14. wise.) It is therefore the responsibility of the user to acquire
  15. whatever license(s) may be required for legal use of this code.
  16. THE INFO-ZIP GROUP DISCLAIMS ALL LIABILITY FOR USE OF THIS CODE
  17. IN VIOLATION OF APPLICABLE PATENT LAW.
  18. Shrinking is basically a dynamic LZW algorithm with allowed code sizes of
  19. up to 13 bits; in addition, there is provision for partial clearing of
  20. leaf nodes. PKWARE uses the special code 256 (decimal) to indicate a
  21. change in code size or a partial clear of the code tree: 256,1 for the
  22. former and 256,2 for the latter. [Note that partial clearing can "orphan"
  23. nodes: the parent-to-be can be cleared before its new child is added,
  24. but the child is added anyway (as an orphan, as though the parent still
  25. existed). When the tree fills up to the point where the parent node is
  26. reused, the orphan is effectively "adopted." Versions prior to 1.05 were
  27. affected more due to greater use of pointers (to children and siblings
  28. as well as parents).]
  29. This replacement version of unshrink.c was written from scratch. It is
  30. based only on the algorithms described in Mark Nelson's _The Data Compres-
  31. sion Book_ and in Terry Welch's original paper in the June 1984 issue of
  32. IEEE _Computer_; no existing source code, including any in Nelson's book,
  33. was used.
  34. Memory requirements have been reduced in this version and are now no more
  35. than the original Sam Smith code. This is still larger than any of the
  36. other algorithms: at a minimum, 8K+8K+16K (stack+values+parents) assuming
  37. 16-bit short ints, and this does not even include the output buffer (the
  38. other algorithms leave the uncompressed data in the work area, typically
  39. called slide[]). For machines with a 64KB data space this is a problem,
  40. particularly when text conversion is required and line endings have more
  41. than one character. UnZip's solution is to use two roughly equal halves
  42. of outbuf for the ASCII conversion in such a case; the "unshrink" argument
  43. to flush() signals that this is the case.
  44. For large-memory machines, a second outbuf is allocated for translations,
  45. but only if unshrinking and only if translations are required.
  46. | binary mode | text mode
  47. ---------------------------------------------------
  48. big mem | big outbuf | big outbuf + big outbuf2 <- malloc'd here
  49. small mem | small outbuf | half + half small outbuf
  50. Copyright 1994, 1995 Greg Roelofs. See the accompanying file "COPYING"
  51. in UnZip 5.20 (or later) source or binary distributions.
  52. From "COPYING":
  53. The following copyright applies to the new version of unshrink.c,
  54. distributed with UnZip version 5.2 and later:
  55. * Copyright (c) 1994 Greg Roelofs.
  56. * Permission is granted to any individual/institution/corporate
  57. * entity to use, copy, redistribute or modify this software for
  58. * any purpose whatsoever, subject to the conditions noted in the
  59. * Frequently Asked Questions section below, plus one additional
  60. * condition: namely, that my name not be removed from the source
  61. * code. (Other names may, of course, be added as modifications
  62. * are made.) Corporate legal staff (like at IBM :-) ) who have
  63. * problems understanding this can contact me through Zip-Bugs...
  64. Q. Can I use the source code of Zip and UnZip in my commercial
  65. application?
  66. A. Yes, so long as you include in your product an acknowledgment; a
  67. pointer to the original, free compression sources; and a statement
  68. making it clear that there are no extra or hidden charges resulting
  69. from the use of our compression code in your product (see below for
  70. an example). The acknowledgment should appear in at least one piece
  71. of human-readable documentation (e.g., a README file or man page),
  72. although additionally putting it in the executable(s) is OK, too.
  73. In other words, you are allowed to sell only your own work, not ours,
  74. and we'd like a little credit. (Note the additional restrictions
  75. above on the code in unreduce.c, unshrink.c, vms.c, time_lib.c, and
  76. everything in the wince and windll subdirectories.) Contact us at
  77. Zip-Bugs@lists.wku.edu if you have special requirements. We also
  78. like to hear when our code is being used, but we don't require that.
  79. <Product> incorporates compression code from the Info-ZIP group.
  80. There are no extra charges or costs due to the use of this code,
  81. and the original compression sources are freely available from
  82. http://www.cdrom.com/pub/infozip/ or ftp://ftp.cdrom.com/pub/infozip/
  83. on the Internet.
  84. If you only need compression capability, not full zipfile support,
  85. you might want to look at zlib instead; it has fewer restrictions
  86. on commercial use. See http://www.cdrom.com/pub/infozip/zlib/ .
  87. ---------------------------------------------------------------------------*/
  88. #include <string.h>
  89. #include <stdio.h>
  90. #include "cpio.h"
  91. #include "unzip.h"
  92. static void partial_clear(struct globals *);
  93. #define trace()
  94. /* HSIZE is defined as 2^13 (8192) in unzip.h */
  95. #define BOGUSCODE 256
  96. #define FLAG_BITS parent /* upper bits of parent[] used as flag bits */
  97. #define CODE_MASK (HSIZE - 1) /* 0x1fff (lower bits are parent's index) */
  98. #define FREE_CODE HSIZE /* 0x2000 (code is unused or was cleared) */
  99. #define HAS_CHILD (HSIZE << 1) /* 0x4000 (code has a child--do not clear) */
  100. #define parent G.area.shrink.Parent
  101. #define Value G.area.shrink.value /* "value" conflicts with Pyramid ioctl.h */
  102. #define stack G.area.shrink.Stack
  103. /***********************/
  104. /* Function unshrink() */
  105. /***********************/
  106. int
  107. zipunshrink(struct file *f, const char *tgt, int tfd, int doswap, uint32_t *crc)
  108. {
  109. struct globals G;
  110. int offset = (HSIZE - 1);
  111. uint8_t *stacktop = stack + offset;
  112. register uint8_t *newstr;
  113. int codesize=9, len, KwKwK;
  114. int16_t code, oldcode, freecode, curcode;
  115. int16_t lastfreecode;
  116. unsigned int outbufsiz;
  117. /*---------------------------------------------------------------------------
  118. Initialize various variables.
  119. ---------------------------------------------------------------------------*/
  120. memset(&G, 0, sizeof G);
  121. G.tgt = tgt;
  122. G.tfd = tfd;
  123. G.doswap = doswap;
  124. G.crc = crc;
  125. G.zsize = G.uzsize = f->f_csize;
  126. lastfreecode = BOGUSCODE;
  127. for (code = 0; code < BOGUSCODE; ++code) {
  128. Value[code] = (uint8_t)code;
  129. parent[code] = BOGUSCODE;
  130. }
  131. for (code = BOGUSCODE+1; code < HSIZE; ++code)
  132. parent[code] = FREE_CODE;
  133. outbufsiz = OUTBUFSIZ;
  134. G.outptr = G.outbuf;
  135. G.outcnt = 0L;
  136. /*---------------------------------------------------------------------------
  137. Get and output first code, then loop over remaining ones.
  138. ---------------------------------------------------------------------------*/
  139. READBITS(codesize, oldcode)
  140. if (!G.zipeof) {
  141. *G.outptr++ = (uint8_t)oldcode;
  142. ++G.outcnt;
  143. }
  144. do {
  145. READBITS(codesize, code)
  146. if (G.zipeof)
  147. break;
  148. if (code == BOGUSCODE) { /* possible to have consecutive escapes? */
  149. READBITS(codesize, code)
  150. if (code == 1) {
  151. ++codesize;
  152. Trace((stderr, " (codesize now %d bits)\n", codesize));
  153. } else if (code == 2) {
  154. Trace((stderr, " (partial clear code)\n"));
  155. partial_clear(&G); /* clear leafs (nodes with no children) */
  156. Trace((stderr, " (done with partial clear)\n"));
  157. lastfreecode = BOGUSCODE; /* reset start of free-node search */
  158. }
  159. continue;
  160. }
  161. /*-----------------------------------------------------------------------
  162. Translate code: traverse tree from leaf back to root.
  163. -----------------------------------------------------------------------*/
  164. newstr = stacktop;
  165. curcode = code;
  166. if (parent[curcode] == FREE_CODE) {
  167. /* or (FLAG_BITS[curcode] & FREE_CODE)? */
  168. KwKwK = TRUE;
  169. Trace((stderr, " (found a KwKwK code %d; oldcode = %d)\n", code,
  170. oldcode));
  171. --newstr; /* last character will be same as first character */
  172. curcode = oldcode;
  173. } else
  174. KwKwK = FALSE;
  175. do {
  176. *newstr-- = Value[curcode];
  177. curcode = (int16_t)(parent[curcode] & CODE_MASK);
  178. } while (curcode != BOGUSCODE);
  179. len = (int)(stacktop - newstr++);
  180. if (KwKwK)
  181. *stacktop = *newstr;
  182. /*-----------------------------------------------------------------------
  183. Write expanded string in reverse order to output buffer.
  184. -----------------------------------------------------------------------*/
  185. Trace((stderr, "code %4d; oldcode %4d; char %3d (%c); string [", code,
  186. oldcode, (int)(*newstr), (*newstr<32 || *newstr>=127)? ' ':*newstr));
  187. {
  188. register uint8_t *p;
  189. for (p = newstr; p < newstr+len; ++p) {
  190. *G.outptr++ = *p;
  191. if (++G.outcnt == outbufsiz) {
  192. flush(&G, G.outbuf, G.outcnt);
  193. G.outptr = G.outbuf;
  194. G.outcnt = 0L;
  195. }
  196. }
  197. }
  198. /*-----------------------------------------------------------------------
  199. Add new leaf (first character of newstr) to tree as child of oldcode.
  200. -----------------------------------------------------------------------*/
  201. /* search for freecode */
  202. freecode = (int16_t)(lastfreecode + 1);
  203. /* add if-test before loop for speed? */
  204. while (parent[freecode] != FREE_CODE)
  205. ++freecode;
  206. lastfreecode = freecode;
  207. Trace((stderr, "]; newcode %d\n", freecode));
  208. Value[freecode] = *newstr;
  209. parent[freecode] = oldcode;
  210. oldcode = code;
  211. } while (!G.zipeof);
  212. /*---------------------------------------------------------------------------
  213. Flush any remaining data and return to sender...
  214. ---------------------------------------------------------------------------*/
  215. if (G.outcnt > 0L)
  216. flush(&G, G.outbuf, G.outcnt);
  217. return G.status;
  218. } /* end function unshrink() */
  219. /****************************/
  220. /* Function partial_clear() */ /* no longer recursive... */
  221. /****************************/
  222. static void
  223. partial_clear(struct globals *Gp)
  224. {
  225. #define G (*Gp)
  226. register int16_t code;
  227. /* clear all nodes which have no children (i.e., leaf nodes only) */
  228. /* first loop: mark each parent as such */
  229. for (code = BOGUSCODE+1; code < HSIZE; ++code) {
  230. register int16_t cparent = (int16_t)(parent[code] & CODE_MASK);
  231. if (cparent > BOGUSCODE && cparent != FREE_CODE)
  232. FLAG_BITS[cparent] |= HAS_CHILD; /* set parent's child-bit */
  233. }
  234. /* second loop: clear all nodes *not* marked as parents; reset flag bits */
  235. for (code = BOGUSCODE+1; code < HSIZE; ++code) {
  236. if (FLAG_BITS[code] & HAS_CHILD) /* just clear child-bit */
  237. FLAG_BITS[code] &= ~HAS_CHILD;
  238. else { /* leaf: lose it */
  239. Trace((stderr, "%d\n", code));
  240. parent[code] = FREE_CODE;
  241. }
  242. }
  243. return;
  244. }