LZW.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /* Catacomb Apocalypse Source Code
  2. * Copyright (C) 1993-2014 Flat Rock Software
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. //===========================================================================
  19. //
  20. // LZW COMPRESSION ROUTINES
  21. // VERSION 1.1
  22. //
  23. // Compression algrythim by Haruhiko OKUMURA
  24. // Implementation by Jim T. Row
  25. //
  26. //
  27. // Copyright (c) 1992 - Softdisk Publishing inc. - All rights reserved
  28. //
  29. //===========================================================================
  30. //
  31. //
  32. //---------------------------------------------------------------------------
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <ctype.h>
  37. #include <alloc.h>
  38. #include <fcntl.h>
  39. #include <dos.h>
  40. #include <io.h>
  41. #include "lzw.h"
  42. #include "jam_io.h"
  43. //===========================================================================
  44. //
  45. // SWITCHES
  46. //
  47. // NOTE : Make sure the appropriate switches are set in SOFT.c for Softlib
  48. // archive support.
  49. //
  50. //===========================================================================
  51. #define INCLUDE_LZW_COMP 0
  52. #define INCLUDE_LZW_DECOMP 1
  53. //===========================================================================
  54. //
  55. // DEFINES
  56. //
  57. //===========================================================================
  58. #define LZW_N 4096
  59. #define LZW_F 18
  60. #define LZW_THRESHOLD 2 // encode string into position and
  61. // length if match_length is greater
  62. // than this
  63. #define LZW_NIL LZW_N // index for root of bin search trees
  64. //============================================================================
  65. //
  66. // GLOBAL VARIABLES NECESSARY FOR
  67. //
  68. // COMP/DECOMP ROUTINES.
  69. //
  70. //============================================================================
  71. unsigned char far LZW_ring_buffer[LZW_N + LZW_F - 1]; // ring buffer of size
  72. // LZW_N, with extra
  73. // LZW_F-1 bytes to
  74. // facilitate
  75. // string comparison
  76. #if INCLUDE_LZW_COMP
  77. int LZW_match_pos, // MAtchLength of longest match. These are set by the
  78. // InsertNode() procedure.
  79. LZW_match_len,
  80. // left & right children & parents -- These constitute binary search trees. */
  81. LZW_left_child[LZW_N + 1],
  82. LZW_right_child[LZW_N + 257],
  83. LZW_parent[LZW_N + 1];
  84. #endif
  85. //============================================================================
  86. //
  87. // LZW DISPLAY VECTORS
  88. //
  89. // These vectors allow you to hook up any form of display you desire for
  90. // displaying the compression/decompression status.
  91. //
  92. // These routines are called inside of the compression/decompression routines
  93. // and pass the orginal size of data and current position within that
  94. // data. This allows for any kind of "% Done" messages.
  95. //
  96. // Your functions MUST have the following parameters in this order...
  97. //
  98. // void VectorRoutine(unsigned long OrginalSize,unsigned long CurPosition)
  99. //
  100. //
  101. void (*LZW_CompressDisplayVector)() = NULL;
  102. void (*LZW_DecompressDisplayVector)() = NULL;
  103. //============================================================================
  104. //
  105. // SUPPORT ROUTINES FOR LZW COMPRESSION
  106. //
  107. //============================================================================
  108. #if INCLUDE_LZW_COMP
  109. static void InitLZWTree(void) /* initialize trees */
  110. {
  111. int i;
  112. /* For i = 0 to LZW_N - 1, LZW_right_child[i] and LZW_left_child[i] will be the right and
  113. left children of node i. These nodes need not be initialized.
  114. Also, LZW_parent[i] is the parent of node i. These are initialized to
  115. LZW_NIL (= LZW_N), which stands for 'not used.'
  116. For i = 0 to 255, LZW_right_child[LZW_N + i + 1] is the root of the tree
  117. for strings that begin with character i. These are initialized
  118. to LZW_NIL. Note there are 256 trees. */
  119. for (i = LZW_N + 1; i <= LZW_N + 256; i++)
  120. LZW_right_child[i] = LZW_NIL;
  121. for (i = 0; i < LZW_N; i++)
  122. LZW_parent[i] = LZW_NIL;
  123. }
  124. ////////////////////////////////////////////////////////////////////////////
  125. static void InsertLZWNode(unsigned long r)
  126. /* Inserts string of length LZW_F, LZW_ring_buffer[r..r+LZW_F-1], into one of the
  127. trees (LZW_ring_buffer[r]'th tree) and returns the longest-match position
  128. and length via the global variables LZW_match_pos and LZW_match_len.
  129. If LZW_match_len = LZW_F, then removes the old node in favor of the new
  130. one, because the old one will be deleted sooner.
  131. Note r plays double role, as tree node and position in buffer. */
  132. {
  133. int i, p, cmp;
  134. unsigned char *key;
  135. cmp = 1;
  136. key = &LZW_ring_buffer[r];
  137. p = LZW_N + 1 + key[0];
  138. LZW_right_child[r] = LZW_left_child[r] = LZW_NIL;
  139. LZW_match_len = 0;
  140. for ( ; ; )
  141. {
  142. if (cmp >= 0)
  143. {
  144. if (LZW_right_child[p] != LZW_NIL)
  145. p = LZW_right_child[p];
  146. else
  147. {
  148. LZW_right_child[p] = r;
  149. LZW_parent[r] = p;
  150. return;
  151. }
  152. }
  153. else
  154. {
  155. if (LZW_left_child[p] != LZW_NIL)
  156. p = LZW_left_child[p];
  157. else
  158. {
  159. LZW_left_child[p] = r;
  160. LZW_parent[r] = p;
  161. return;
  162. }
  163. }
  164. for (i = 1; i < LZW_F; i++)
  165. if ((cmp = key[i] - LZW_ring_buffer[p + i]) != 0)
  166. break;
  167. if (i > LZW_match_len)
  168. {
  169. LZW_match_pos = p;
  170. if ((LZW_match_len = i) >= LZW_F)
  171. break;
  172. }
  173. }
  174. LZW_parent[r] = LZW_parent[p];
  175. LZW_left_child[r] = LZW_left_child[p];
  176. LZW_right_child[r] = LZW_right_child[p];
  177. LZW_parent[LZW_left_child[p]] = r;
  178. LZW_parent[LZW_right_child[p]] = r;
  179. if (LZW_right_child[LZW_parent[p]] == p)
  180. LZW_right_child[LZW_parent[p]] = r;
  181. else
  182. LZW_left_child[LZW_parent[p]] = r;
  183. LZW_parent[p] = LZW_NIL; /* remove p */
  184. }
  185. ////////////////////////////////////////////////////////////////////////////
  186. static void DeleteLZWNode(unsigned long p) /* deletes node p from tree */
  187. {
  188. int q;
  189. if (LZW_parent[p] == LZW_NIL)
  190. return; /* not in tree */
  191. if (LZW_right_child[p] == LZW_NIL)
  192. q = LZW_left_child[p];
  193. else
  194. if (LZW_left_child[p] == LZW_NIL)
  195. q = LZW_right_child[p];
  196. else
  197. {
  198. q = LZW_left_child[p];
  199. if (LZW_right_child[q] != LZW_NIL)
  200. {
  201. do {
  202. q = LZW_right_child[q];
  203. } while (LZW_right_child[q] != LZW_NIL);
  204. LZW_right_child[LZW_parent[q]] = LZW_left_child[q];
  205. LZW_parent[LZW_left_child[q]] = LZW_parent[q];
  206. LZW_left_child[q] = LZW_left_child[p];
  207. LZW_parent[LZW_left_child[p]] = q;
  208. }
  209. LZW_right_child[q] = LZW_right_child[p];
  210. LZW_parent[LZW_right_child[p]] = q;
  211. }
  212. LZW_parent[q] = LZW_parent[p];
  213. if (LZW_right_child[LZW_parent[p]] == p)
  214. LZW_right_child[LZW_parent[p]] = q;
  215. else
  216. LZW_left_child[LZW_parent[p]] = q;
  217. LZW_parent[p] = LZW_NIL;
  218. }
  219. //--------------------------------------------------------------------------
  220. //
  221. // lzwCompress() - Compresses data from an input ptr to a dest ptr
  222. //
  223. // PARAMS:
  224. // infile - Pointer at the BEGINNING of the data to compress
  225. // outfile - Pointer to the destination (no header).
  226. // DataLength - Number of bytes to compress.
  227. // PtrTypes - Type of pointers being used (SRC_FILE,DEST_FILE,SRC_MEM etc).
  228. //
  229. // RETURNS:
  230. // Length of compressed data.
  231. //
  232. // COMPTYPE : ct_LZW
  233. //
  234. // NOTES : Does not write ANY header information!
  235. //
  236. unsigned long lzwCompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)
  237. {
  238. short i;
  239. short c, len, r, s, last_LZW_match_len, code_buf_ptr;
  240. unsigned char code_buf[17], mask;
  241. unsigned long complen = 0;
  242. unsigned CodeCount = 0;
  243. unsigned long OrgDataLen = DataLength;
  244. // initialize trees
  245. InitLZWTree();
  246. code_buf[0] = 0;
  247. //
  248. // code_buf[1..16] saves eight units of code, and code_buf[0] works
  249. // as eight flags, "1" representing that the unit is an unencoded
  250. // letter (1 byte), "0" a position-and-length pair (2 bytes). Thus,
  251. // eight units require at most 16 bytes of code.
  252. //
  253. code_buf_ptr = mask = 1;
  254. s = 0;
  255. r = LZW_N - LZW_F;
  256. // Clear the buffer with any character that will appear often.
  257. //
  258. for (i = s; i < r; i++)
  259. LZW_ring_buffer[i] = ' ';
  260. // Read LZW_F bytes into the last LZW_F bytes of the buffer
  261. //
  262. for (len = 0; (len < LZW_F) && DataLength; len++)
  263. {
  264. c = ReadPtr((long)&infile,PtrTypes);
  265. DataLength--;
  266. // text of size zero
  267. LZW_ring_buffer[r + len] = c;
  268. }
  269. if (!(len && DataLength))
  270. return(0);
  271. //
  272. // Insert the LZW_F strings, each of which begins with one or more
  273. // 'space' characters. Note the order in which these strings
  274. // are inserted. This way, degenerate trees will be less likely
  275. // to occur.
  276. //
  277. for (i = 1; i <= LZW_F; i++)
  278. InsertLZWNode(r - i);
  279. //
  280. // Finally, insert the whole string just read. The global
  281. // variables LZW_match_len and LZW_match_pos are set. */
  282. //
  283. InsertLZWNode(r);
  284. do {
  285. // LZW_match_len may be spuriously long near the end of text.
  286. //
  287. if (LZW_match_len > len)
  288. LZW_match_len = len;
  289. if (LZW_match_len <= LZW_THRESHOLD)
  290. {
  291. // Not long enough match. Send one byte.
  292. //
  293. LZW_match_len = 1;
  294. // 'send one byte' flag
  295. //
  296. code_buf[0] |= mask;
  297. // Send uncoded.
  298. //
  299. code_buf[code_buf_ptr++] = LZW_ring_buffer[r];
  300. }
  301. else
  302. {
  303. code_buf[code_buf_ptr++] = (unsigned char) LZW_match_pos;
  304. code_buf[code_buf_ptr++] = (unsigned char) (((LZW_match_pos >> 4) & 0xf0) | (LZW_match_len - (LZW_THRESHOLD + 1)));
  305. // Send position and length pair.
  306. // Note LZW_match_len > LZW_THRESHOLD.
  307. }
  308. if ((mask <<= 1) == 0)
  309. {
  310. // Shift mask left one bit.
  311. // Send at most 8 units of data
  312. for (i = 0; i < code_buf_ptr; i++)
  313. WritePtr((long)&outfile,code_buf[i],PtrTypes);
  314. complen += code_buf_ptr;
  315. code_buf[0] = 0;
  316. code_buf_ptr = mask = 1;
  317. }
  318. last_LZW_match_len = LZW_match_len;
  319. for (i = 0; i < last_LZW_match_len && DataLength; i++)
  320. {
  321. c = ReadPtr((long)&infile,PtrTypes);
  322. DataLength--;
  323. DeleteLZWNode(s); // Delete old strings and
  324. LZW_ring_buffer[s] = c; // read new bytes
  325. // If the position is near the end of buffer, extend the
  326. // buffer to make string comparison easier.
  327. if (s < LZW_F - 1)
  328. LZW_ring_buffer[s + LZW_N] = c;
  329. // Since this is a ring buffer, inc the position modulo LZW_N.
  330. //
  331. s = (s + 1) & (LZW_N - 1);
  332. r = (r + 1) & (LZW_N - 1);
  333. // Register the string in LZW_ring_buffer[r..r+LZW_F-1]
  334. //
  335. InsertLZWNode(r);
  336. }
  337. //
  338. // MANAGE DISPLAY VECTOR
  339. //
  340. if (LZW_CompressDisplayVector)
  341. {
  342. // Update display every 1k!
  343. //
  344. if ((CodeCount += i) > 1024)
  345. {
  346. LZW_CompressDisplayVector(OrgDataLen,OrgDataLen-DataLength);
  347. CodeCount = 0;
  348. }
  349. }
  350. //
  351. // Manage Compression tree..
  352. //
  353. while (i++ < last_LZW_match_len)
  354. {
  355. // After the end of text,
  356. DeleteLZWNode(s); // no need to read, but
  357. s = (s + 1) & (LZW_N - 1);
  358. r = (r + 1) & (LZW_N - 1);
  359. if (--len)
  360. InsertLZWNode(r); // buffer may not be empty.
  361. }
  362. } while (len > 0); // until length of string to be processed is zero
  363. if (code_buf_ptr > 1)
  364. {
  365. // Send remaining code.
  366. //
  367. for (i = 0; i < code_buf_ptr; i++)
  368. WritePtr((long)&outfile,code_buf[i],PtrTypes);
  369. complen += code_buf_ptr;
  370. }
  371. if (LZW_CompressDisplayVector)
  372. {
  373. if ((CodeCount += i) > 1024)
  374. {
  375. LZW_CompressDisplayVector(OrgDataLen,OrgDataLen-DataLength);
  376. }
  377. }
  378. return(complen);
  379. }
  380. #endif
  381. //============================================================================
  382. //
  383. // SUPPORT ROUTINES FOR LZW DECOMPRESSION
  384. //
  385. //============================================================================
  386. #if INCLUDE_LZW_DECOMP
  387. //--------------------------------------------------------------------------
  388. //
  389. // lzwDecompress() - Compresses data from an input ptr to a dest ptr
  390. //
  391. // PARAMS:
  392. // infile - Pointer at the BEGINNING of the compressed data (no header!)
  393. // outfile - Pointer to the destination.
  394. // DataLength - Number of bytes to decompress.
  395. // PtrTypes - Type of pointers being used (SRC_FILE,DEST_FILE,SRC_MEM etc).
  396. //
  397. // RETURNS:
  398. // Length of compressed data.
  399. //
  400. // COMPTYPE : ct_LZW
  401. //
  402. // NOTES : Does not write ANY header information!
  403. //
  404. void lzwDecompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)
  405. {
  406. int i, j, k, r, c;
  407. unsigned int flags;
  408. unsigned char Buffer[8];
  409. // unsigned char LZW_ring_buffer[LZW_N + LZW_F - 1];
  410. unsigned CodeCount = 0;
  411. unsigned long OrgDataLen = DataLength;
  412. for (i = 0; i < LZW_N - LZW_F; i++)
  413. LZW_ring_buffer[i] = ' ';
  414. r = LZW_N - LZW_F;
  415. flags = 0;
  416. for ( ; ; )
  417. {
  418. if (((flags >>= 1) & 256) == 0)
  419. {
  420. c = ReadPtr((long)&infile,PtrTypes);
  421. flags = c | 0xff00; // uses higher byte cleverly to count 8
  422. }
  423. if (flags & 1)
  424. {
  425. c = ReadPtr((long)&infile,PtrTypes); // Could test for EOF iff FFILE type
  426. WritePtr((long)&outfile,c,PtrTypes);
  427. if (!--DataLength)
  428. return;
  429. LZW_ring_buffer[r++] = c;
  430. r &= (LZW_N - 1);
  431. }
  432. else
  433. {
  434. i = ReadPtr((long)&infile,PtrTypes);
  435. j = ReadPtr((long)&infile,PtrTypes);
  436. i |= ((j & 0xf0) << 4);
  437. j = (j & 0x0f) + LZW_THRESHOLD;
  438. for (k = 0; k <= j; k++)
  439. {
  440. c = LZW_ring_buffer[(i + k) & (LZW_N - 1)];
  441. WritePtr((long)&outfile,c,PtrTypes);
  442. if (!--DataLength)
  443. return;
  444. LZW_ring_buffer[r++] = c;
  445. r &= (LZW_N - 1);
  446. }
  447. }
  448. //
  449. // MANAGE DISPLAY VECTOR
  450. //
  451. if (LZW_DecompressDisplayVector)
  452. {
  453. //
  454. // Update DisplayVector every 1K
  455. //
  456. if ((CodeCount+=k) > 1024)
  457. {
  458. LZW_DecompressDisplayVector(OrgDataLen,OrgDataLen-DataLength);
  459. CodeCount = 0;
  460. }
  461. }
  462. }
  463. }
  464. #endif