]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/JAMPAK.C
wwww
[16.git] / 16 / cawat / JAMPAK.C
1 /* Catacomb Armageddon Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 #pragma inline\r
20 \r
21 #include <stdio.h>\r
22 #include <stdlib.h>\r
23 #include <string.h>\r
24 #include <ctype.h>\r
25 #include <alloc.h>\r
26 #include <fcntl.h>\r
27 #include <dos.h>\r
28 #include <io.h>\r
29 \r
30 #include "def.h"\r
31 #include "gelib.h"\r
32 #include "jampak.h"\r
33 \r
34 \r
35 \r
36 //=========================================================================\r
37 //\r
38 //\r
39 //                                                                      LOCAL DEFINATIONS\r
40 //\r
41 //\r
42 //=========================================================================\r
43 \r
44 //#define COMPRESSION_CODE                              // Comment define in for COMPRESS routines\r
45 \r
46 \r
47 \r
48 \r
49 \r
50 \r
51 //=========================================================================\r
52 //\r
53 //\r
54 //                                                                      LOCAL VARIABLES\r
55 //\r
56 //\r
57 //=========================================================================\r
58 \r
59 \r
60 unsigned char far LZW_ring_buffer[LZW_N + LZW_F - 1];\r
61 \r
62         // ring buffer of size LZW_N, with extra LZW_F-1 bytes to facilitate\r
63         //      string comparison\r
64 \r
65 \r
66 #ifdef COMPRESSION_CODE\r
67 \r
68 int LZW_match_pos,\r
69          LZW_match_len,\r
70 \r
71         // MAtchLength of longest match.  These are set by the InsertNode()\r
72         //      procedure.\r
73 \r
74         // left & right children & parents -- These constitute binary search trees. */\r
75 \r
76         far LZW_left_child[LZW_N + 1],\r
77         far LZW_right_child[LZW_N + 257],\r
78         far LZW_parent[LZW_N + 1];\r
79 \r
80 #endif\r
81 \r
82 memptr segptr;\r
83 BufferedIO lzwBIO;\r
84 \r
85 \r
86 \r
87 \r
88 \r
89 //=========================================================================\r
90 //\r
91 //\r
92 //                                                                      COMPRESSION SUPPORT ROUTINES\r
93 //\r
94 //\r
95 //=========================================================================\r
96 \r
97 \r
98 #ifdef COMPRESSION_CODE\r
99 \r
100 //---------------------------------------------------------------------------\r
101 // InitLZWTree()\r
102 //---------------------------------------------------------------------------\r
103 void InitLZWTree(void)  /* initialize trees */\r
104 {\r
105          int i;\r
106 \r
107          /* For i = 0 to LZW_N - 1, LZW_right_child[i] and LZW_left_child[i] will be the right and\r
108                  left children of node i.  These nodes need not be initialized.\r
109                  Also, LZW_parent[i] is the parent of node i.  These are initialized to\r
110                  LZW_NIL (= LZW_N), which stands for 'not used.'\r
111                  For i = 0 to 255, LZW_right_child[LZW_N + i + 1] is the root of the tree\r
112                  for strings that begin with character i.  These are initialized\r
113                  to LZW_NIL.  Note there are 256 trees. */\r
114 \r
115          for (i = LZW_N + 1; i <= LZW_N + 256; i++)\r
116                 LZW_right_child[i] = LZW_NIL;\r
117 \r
118          for (i = 0; i < LZW_N; i++)\r
119                 LZW_parent[i] = LZW_NIL;\r
120 }\r
121 \r
122 \r
123 \r
124 \r
125 \r
126 //---------------------------------------------------------------------------\r
127 // InsertLZWNode()\r
128 //---------------------------------------------------------------------------\r
129 void InsertLZWNode(unsigned long r)\r
130 \r
131          /* Inserts string of length LZW_F, LZW_ring_buffer[r..r+LZW_F-1], into one of the\r
132                  trees (LZW_ring_buffer[r]'th tree) and returns the longest-match position\r
133                  and length via the global variables LZW_match_pos and LZW_match_len.\r
134                  If LZW_match_len = LZW_F, then removes the old node in favor of the new\r
135                  one, because the old one will be deleted sooner.\r
136                  Note r plays double role, as tree node and position in buffer. */\r
137 {\r
138          int  i, p, cmp;\r
139          unsigned char *key;\r
140 \r
141          cmp = 1;\r
142          key = &LZW_ring_buffer[r];\r
143          p = LZW_N + 1 + key[0];\r
144          LZW_right_child[r] = LZW_left_child[r] = LZW_NIL;\r
145          LZW_match_len = 0;\r
146 \r
147         for ( ; ; )\r
148         {\r
149                 if (cmp >= 0)\r
150                 {\r
151                         if (LZW_right_child[p] != LZW_NIL)\r
152                                 p = LZW_right_child[p];\r
153                         else\r
154                         {\r
155                                 LZW_right_child[p] = r;\r
156                                 LZW_parent[r] = p;\r
157                                 return;\r
158                         }\r
159                 }\r
160                 else\r
161                 {\r
162                         if (LZW_left_child[p] != LZW_NIL)\r
163                                 p = LZW_left_child[p];\r
164                         else\r
165                         {\r
166                                 LZW_left_child[p] = r;\r
167                                 LZW_parent[r] = p;\r
168                                 return;\r
169                         }\r
170                 }\r
171 \r
172                 for (i = 1; i < LZW_F; i++)\r
173                         if ((cmp = key[i] - LZW_ring_buffer[p + i]) != 0)\r
174                                 break;\r
175 \r
176                 if (i > LZW_match_len)\r
177                 {\r
178                         LZW_match_pos = p;\r
179                         if ((LZW_match_len = i) >= LZW_F)\r
180                                 break;\r
181                 }\r
182         }\r
183 \r
184         LZW_parent[r] = LZW_parent[p];\r
185         LZW_left_child[r] = LZW_left_child[p];\r
186         LZW_right_child[r] = LZW_right_child[p];\r
187         LZW_parent[LZW_left_child[p]] = r;\r
188         LZW_parent[LZW_right_child[p]] = r;\r
189 \r
190         if (LZW_right_child[LZW_parent[p]] == p)\r
191                 LZW_right_child[LZW_parent[p]] = r;\r
192         else\r
193                 LZW_left_child[LZW_parent[p]] = r;\r
194 \r
195         LZW_parent[p] = LZW_NIL;  /* remove p */\r
196 }\r
197 \r
198 \r
199 \r
200 //---------------------------------------------------------------------------\r
201 // DeleteLZWNode()\r
202 //---------------------------------------------------------------------------\r
203 void DeleteLZWNode(unsigned long p)  /* deletes node p from tree */\r
204 {\r
205         int q;\r
206 \r
207         if (LZW_parent[p] == LZW_NIL)\r
208                 return;                                          /* not in tree */\r
209 \r
210         if (LZW_right_child[p] == LZW_NIL)\r
211                 q = LZW_left_child[p];\r
212         else\r
213         if (LZW_left_child[p] == LZW_NIL)\r
214                 q = LZW_right_child[p];\r
215         else\r
216         {\r
217                 q = LZW_left_child[p];\r
218                 if (LZW_right_child[q] != LZW_NIL)\r
219                 {\r
220                         do {\r
221 \r
222                                 q = LZW_right_child[q];\r
223 \r
224                         } while (LZW_right_child[q] != LZW_NIL);\r
225 \r
226                         LZW_right_child[LZW_parent[q]] = LZW_left_child[q];\r
227                         LZW_parent[LZW_left_child[q]] = LZW_parent[q];\r
228                         LZW_left_child[q] = LZW_left_child[p];\r
229                         LZW_parent[LZW_left_child[p]] = q;\r
230                 }\r
231 \r
232                 LZW_right_child[q] = LZW_right_child[p];\r
233                 LZW_parent[LZW_right_child[p]] = q;\r
234          }\r
235 \r
236          LZW_parent[q] = LZW_parent[p];\r
237          if (LZW_right_child[LZW_parent[p]] == p)\r
238                 LZW_right_child[LZW_parent[p]] = q;\r
239          else\r
240                 LZW_left_child[LZW_parent[p]] = q;\r
241 \r
242          LZW_parent[p] = LZW_NIL;\r
243 }\r
244 #endif\r
245 \r
246 \r
247 \r
248 \r
249 //=========================================================================\r
250 //\r
251 //\r
252 //                                                      GENERAL FILE to FILE compression routines\r
253 //\r
254 //      * Mainly for example usage of PTR/PTR (de)compression routines.\r
255 //\r
256 //\r
257 //=========================================================================\r
258 \r
259 \r
260 \r
261 //////////////////////////////////////////////////////////////////////\r
262 //\r
263 //  CompressFILEtoFILE() -- Compresses one file stream to another file stream\r
264 //\r
265 \r
266 #ifdef COMPRESSION_CODE\r
267 \r
268 unsigned long CompressFILEtoFILE(FILE *infile, FILE *outfile,unsigned long DataLength)\r
269 {\r
270         unsigned long returnval;\r
271 \r
272         fwrite(COMP,4,1,outfile);\r
273         fwrite((char *)&DataLength,4,1,outfile);\r
274 \r
275         returnval = 8+lzwCompress(infile,outfile,DataLength,(SRC_FFILE|DEST_FFILE));\r
276 \r
277         return(returnval);\r
278 }\r
279 \r
280 #endif\r
281 \r
282 #if 0\r
283 /////////////////////////////////////////////////////////////////////////////\r
284 //\r
285 //  DecompressFILEtoFILE()\r
286 //\r
287 void DecompressFILEtoFILE(FILE *infile, FILE *outfile)\r
288 {\r
289         unsigned char Buffer[8];\r
290         unsigned long DataLength;\r
291 \r
292         fread(Buffer,1,4,infile);\r
293 \r
294         if (strncmp(Buffer,COMP,4))\r
295         {\r
296                 printf("\nNot a JAM Compressed File!\n");\r
297                 return;\r
298         }\r
299 \r
300         fread((void *)&DataLength,1,4,infile);\r
301 \r
302         lzwDecompress(infile,outfile,DataLength,(SRC_FFILE|DEST_FFILE));\r
303 }\r
304 #endif\r
305 \r
306 \r
307 \r
308 \r
309 \r
310 //==========================================================================\r
311 //\r
312 //\r
313 //                                                      WRITE/READ PTR ROUTINES\r
314 //\r
315 //\r
316 //==========================================================================\r
317 \r
318 \r
319 \r
320 //---------------------------------------------------------------------------\r
321 // WritePtr()  -- Outputs data to a particular ptr type\r
322 //\r
323 //      PtrType MUST be of type DEST_TYPE.\r
324 //\r
325 // NOTE : For PtrTypes DEST_MEM a ZERO (0) is always returned.\r
326 //\r
327 //---------------------------------------------------------------------------\r
328 int WritePtr(long outfile, unsigned char data, unsigned PtrType)\r
329 {\r
330         int returnval = 0;\r
331 \r
332         switch (PtrType & DEST_TYPES)\r
333         {\r
334                 case DEST_FILE:\r
335                         write(*(int far *)outfile,(char *)&data,1);\r
336                 break;\r
337 \r
338                 case DEST_FFILE:\r
339                         returnval = putc(data, *(FILE **)outfile);\r
340                 break;\r
341 \r
342                 case DEST_MEM:\r
343 //                      *(*(char far **)outfile++) = data;                                              // Do NOT delete\r
344                         *((char far *)*(char far **)outfile)++ = data;\r
345                 break;\r
346 \r
347                 default:\r
348                         TrashProg("WritePtr() : Unknown DEST_PTR type");\r
349                 break;\r
350         }\r
351 \r
352         return(returnval);\r
353 \r
354 }\r
355 \r
356 \r
357 //---------------------------------------------------------------------------\r
358 // ReadPtr()  -- Reads data from a particular ptr type\r
359 //\r
360 //      PtrType MUST be of type SRC_TYPE.\r
361 //\r
362 // RETURNS :\r
363 //              The char read in or EOF for SRC_FFILE type of reads.\r
364 //\r
365 //\r
366 //---------------------------------------------------------------------------\r
367 int ReadPtr(long infile, unsigned PtrType)\r
368 {\r
369         int returnval = 0;\r
370 \r
371         switch (PtrType & SRC_TYPES)\r
372         {\r
373                 case SRC_FILE:\r
374                         read(*(int far *)infile,(char *)&returnval,1);\r
375                 break;\r
376 \r
377                 case SRC_FFILE:\r
378 // JIM - JTR - is the following correct? "fgetc()" uses a near pointer.\r
379 //\r
380                         returnval = fgetc((FILE far *)*(FILE far **)infile);\r
381                 break;\r
382 \r
383                 case SRC_BFILE:\r
384                         returnval = bio_readch((BufferedIO *)*(void far **)infile);\r
385                 break;\r
386 \r
387                 case SRC_MEM:\r
388                         returnval = (char)*(*(char far **)infile++);\r
389 //                      returnval = *((char far *)*(char far **)infile)++;      // DO NOT DELETE!\r
390                 break;\r
391 \r
392                 default:\r
393                         TrashProg("ReadPtr() : Unknown SRC_PTR type");\r
394                 break;\r
395         }\r
396 \r
397         return(returnval);\r
398 }\r
399 \r
400 \r
401 \r
402 \r
403 //=========================================================================\r
404 //\r
405 //\r
406 //                                                      COMPRESSION & DECOMPRESSION ROUTINES\r
407 //\r
408 //\r
409 //=========================================================================\r
410 \r
411 \r
412 //--------------------------------------------------------------------------\r
413 //\r
414 // lzwCompress() - Compresses data from an input ptr to a dest ptr\r
415 //\r
416 // PARAMS:\r
417 //               infile     - Pointer at the BEGINNING of the data to compress\r
418 //               outfile    - Pointer to the destination (no header).\r
419 //       DataLength - Number of bytes to compress.\r
420 //     PtrTypes   - Type of pointers being used (SRC_FILE,DEST_FILE,SRC_MEM etc).\r
421 //\r
422 // RETURNS:\r
423 //          Length of compressed data.\r
424 //\r
425 //      COMPTYPE : ct_LZW\r
426 //\r
427 // NOTES    : Does not write ANY header information!\r
428 //\r
429 #ifdef COMPRESSION_CODE\r
430 unsigned long lzwCompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)\r
431 {\r
432         short i;\r
433         short c, len, r, s, last_LZW_match_len, code_buf_ptr;\r
434         unsigned char far code_buf[17], mask;\r
435         unsigned long complen = 0;\r
436 \r
437         // initialize trees\r
438 \r
439         InitLZWTree();\r
440 \r
441         code_buf[0] = 0;\r
442 \r
443         //\r
444         //  code_buf[1..16] saves eight units of code, and code_buf[0] works\r
445         //       as eight flags, "1" representing that the unit is an unencoded\r
446         //       letter (1 byte), "0" a position-and-length pair (2 bytes).  Thus,\r
447         //       eight units require at most 16 bytes of code.\r
448         //\r
449 \r
450          code_buf_ptr = mask = 1;\r
451          s = 0;\r
452          r = LZW_N - LZW_F;\r
453 \r
454         // Clear the buffer with any character that will appear often.\r
455         //\r
456 \r
457          for (i = s; i < r; i++)\r
458                         LZW_ring_buffer[i] = ' ';\r
459 \r
460         // Read LZW_F bytes into the last LZW_F bytes of the buffer\r
461         //\r
462 \r
463          for (len = 0; (len < LZW_F) && DataLength; len++)\r
464          {\r
465                 c = ReadPtr((long)&infile,PtrTypes);\r
466                 DataLength--;\r
467 \r
468                 // text of size zero\r
469 \r
470                 LZW_ring_buffer[r + len] = c;\r
471          }\r
472 \r
473          if (!(len && DataLength))\r
474                 return(0);\r
475 \r
476         //\r
477         // Insert the LZW_F strings, each of which begins with one or more\r
478         // 'space' characters.  Note the order in which these strings\r
479         // are inserted.  This way, degenerate trees will be less likely\r
480         // to occur.\r
481         //\r
482 \r
483          for (i = 1; i <= LZW_F; i++)\r
484                         InsertLZWNode(r - i);\r
485 \r
486         //\r
487         // Finally, insert the whole string just read.  The global\r
488         // variables LZW_match_len and LZW_match_pos are set. */\r
489         //\r
490 \r
491          InsertLZWNode(r);\r
492 \r
493          do {\r
494                         // LZW_match_len may be spuriously long near the end of text.\r
495                         //\r
496 \r
497                         if (LZW_match_len > len)\r
498                                 LZW_match_len = len;\r
499 \r
500                         if (LZW_match_len <= LZW_THRESHOLD)\r
501                         {\r
502                                   // Not long enough match.  Send one byte.\r
503                                   //\r
504 \r
505                                   LZW_match_len = 1;\r
506 \r
507                                   // 'send one byte' flag\r
508                                   //\r
509 \r
510                                   code_buf[0] |= mask;\r
511 \r
512                                   // Send uncoded.\r
513                                   //\r
514 \r
515                                   code_buf[code_buf_ptr++] = LZW_ring_buffer[r];\r
516                         }\r
517                         else\r
518                         {\r
519                                 code_buf[code_buf_ptr++] = (unsigned char) LZW_match_pos;\r
520                                 code_buf[code_buf_ptr++] = (unsigned char) (((LZW_match_pos >> 4) & 0xf0) | (LZW_match_len - (LZW_THRESHOLD + 1)));\r
521 \r
522                                 // Send position and length pair.\r
523                                 // Note LZW_match_len > LZW_THRESHOLD.\r
524                         }\r
525 \r
526                         if ((mask <<= 1) == 0)\r
527                         {\r
528                                 // Shift mask left one bit.\r
529                                 // Send at most 8 units of data\r
530 \r
531                                 for (i = 0; i < code_buf_ptr; i++)\r
532                                         WritePtr((long)&outfile,code_buf[i],PtrTypes);\r
533 \r
534                                 complen += code_buf_ptr;\r
535                                 code_buf[0] = 0;\r
536                                 code_buf_ptr = mask = 1;\r
537                         }\r
538 \r
539                         last_LZW_match_len = LZW_match_len;\r
540 \r
541                         for (i = 0; i < last_LZW_match_len && DataLength; i++)\r
542                         {\r
543                                 c = ReadPtr((long)&infile,PtrTypes);\r
544                                 DataLength--;\r
545 \r
546                                 DeleteLZWNode(s);                           // Delete old strings and\r
547                                 LZW_ring_buffer[s] = c;                                          // read new bytes\r
548 \r
549                                 // If the position is near the end of buffer, extend the\r
550                                 //      buffer to make string comparison easier.\r
551 \r
552                                 if (s < LZW_F - 1)\r
553                                         LZW_ring_buffer[s + LZW_N] = c;\r
554 \r
555                                 // Since this is a ring buffer, inc the position modulo LZW_N.\r
556                                 //\r
557 \r
558                                 s = (s + 1) & (LZW_N - 1);\r
559                                 r = (r + 1) & (LZW_N - 1);\r
560 \r
561                                 // Register the string in LZW_ring_buffer[r..r+LZW_F-1]\r
562                                 //\r
563 \r
564                                 InsertLZWNode(r);\r
565                         }\r
566 \r
567                         while (i++ < last_LZW_match_len)\r
568                         {\r
569                                                                                                                   // After the end of text,\r
570                                 DeleteLZWNode(s);               // no need to read, but\r
571 \r
572                                 s = (s + 1) & (LZW_N - 1);\r
573                                 r = (r + 1) & (LZW_N - 1);\r
574 \r
575                                 if (--len)\r
576                                         InsertLZWNode(r);          // buffer may not be empty.\r
577                         }\r
578 \r
579          } while (len > 0);  // until length of string to be processed is zero\r
580 \r
581 \r
582          if (code_buf_ptr > 1)\r
583          {\r
584                 // Send remaining code.\r
585                 //\r
586 \r
587                 for (i = 0; i < code_buf_ptr; i++)\r
588                         WritePtr((long)&outfile,code_buf[i],PtrTypes);\r
589 \r
590                 complen += code_buf_ptr;\r
591          }\r
592 \r
593          return(complen);\r
594 }\r
595 #endif\r
596 \r
597 \r
598 \r
599 \r
600 //--------------------------------------------------------------------------\r
601 //\r
602 // lzwDecompress() - Compresses data from an input ptr to a dest ptr\r
603 //\r
604 // PARAMS:\r
605 //               infile     - Pointer at the BEGINNING of the compressed data (no header!)\r
606 //               outfile    - Pointer to the destination.\r
607 //       DataLength - Length of compressed data.\r
608 //     PtrTypes   - Type of pointers being used (SRC_FILE,DEST_FILE,SRC_MEM etc).\r
609 //\r
610 // RETURNS:\r
611 //          Length of compressed data.\r
612 //\r
613 //      COMPTYPE : ct_LZW\r
614 //\r
615 // NOTES    : Does not write ANY header information!\r
616 //\r
617 void far lzwDecompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)\r
618 {\r
619         int  i, j, k, r, c;\r
620         unsigned int flags;\r
621 \r
622         for (i = 0; i < LZW_N - LZW_F; i++)\r
623                 LZW_ring_buffer[i] = ' ';\r
624 \r
625          r = LZW_N - LZW_F;\r
626          flags = 0;\r
627 \r
628          for ( ; ; )\r
629          {\r
630                         if (((flags >>= 1) & 256) == 0)\r
631                         {\r
632                                 c = ReadPtr((long)&infile,PtrTypes);\r
633                                 if (!DataLength--)\r
634                                         return;\r
635 \r
636                                 flags = c | 0xff00;      // uses higher byte cleverly to count 8\r
637                         }\r
638 \r
639                         if (flags & 1)\r
640                         {\r
641                                 c = ReadPtr((long)&infile,PtrTypes);            // Could test for EOF iff FFILE type\r
642                                 if (!DataLength--)\r
643                                         return;\r
644 \r
645                                 WritePtr((long)&outfile,c,PtrTypes);\r
646 \r
647                                 LZW_ring_buffer[r++] = c;\r
648                                 r &= (LZW_N - 1);\r
649                         }\r
650                         else\r
651                         {\r
652                                 i = ReadPtr((long)&infile,PtrTypes);\r
653                            if (!DataLength--)\r
654                                         return;\r
655 \r
656                                 j = ReadPtr((long)&infile,PtrTypes);\r
657                            if (!DataLength--)\r
658                                         return;\r
659 \r
660                                 i |= ((j & 0xf0) << 4);\r
661                                 j = (j & 0x0f) + LZW_THRESHOLD;\r
662 \r
663                                 for (k = 0; k <= j; k++)\r
664                                 {\r
665                                          c = LZW_ring_buffer[(i + k) & (LZW_N - 1)];\r
666 \r
667                                          WritePtr((long)&outfile,c,PtrTypes);\r
668 \r
669                                          LZW_ring_buffer[r++] = c;\r
670                                          r &= (LZW_N - 1);\r
671                                 }\r
672                         }\r
673          }\r
674 }\r
675 \r
676 \r
677 \r
678 #if 0\r
679 //=========================================================================\r
680 //\r
681 //\r
682 //                                                               BUFFERED I/O ROUTINES\r
683 //\r
684 //\r
685 //=========================================================================\r
686 \r
687 \r
688 //--------------------------------------------------------------------------\r
689 // InitBufferedIO()\r
690 //--------------------------------------------------------------------------\r
691 memptr InitBufferedIO(int handle, BufferedIO *bio)\r
692 {\r
693         bio->handle = handle;\r
694         bio->offset = BIO_BUFFER_LEN;\r
695         bio->status = 0;\r
696         MM_GetPtr(&bio->buffer,BIO_BUFFER_LEN);\r
697 \r
698         return(bio->buffer);\r
699 }\r
700 \r
701 \r
702 //--------------------------------------------------------------------------\r
703 // FreeBufferedIO()\r
704 //--------------------------------------------------------------------------\r
705 void FreeBufferedIO(BufferedIO *bio)\r
706 {\r
707         if (bio->buffer)\r
708                 MM_FreePtr(&bio->buffer);\r
709 }\r
710 \r
711 \r
712 //--------------------------------------------------------------------------\r
713 // bio_readch()\r
714 //--------------------------------------------------------------------------\r
715 byte bio_readch(BufferedIO *bio)\r
716 {\r
717         byte far *buffer;\r
718 \r
719         if (bio->offset == BIO_BUFFER_LEN)\r
720         {\r
721                 bio->offset = 0;\r
722                 bio_fillbuffer(bio);\r
723         }\r
724 \r
725         buffer = MK_FP(bio->buffer,bio->offset++);\r
726 \r
727         return(*buffer);\r
728 }\r
729 \r
730 \r
731 //--------------------------------------------------------------------------\r
732 // bio_fillbuffer()\r
733 //\r
734 // BUGS (Not really bugs... More like RULES!)\r
735 //\r
736 //    1) This code assumes BIO_BUFFER_LEN is no smaller than\r
737 //       NEAR_BUFFER_LEN!!\r
738 //\r
739 //    2) BufferedIO.status should be altered by this code to report\r
740 //       read errors, end of file, etc... If you know how big the file\r
741 //       is you're reading, determining EOF should be no problem.\r
742 //\r
743 //--------------------------------------------------------------------------\r
744 void bio_fillbuffer(BufferedIO *bio)\r
745 {\r
746         #define NEAR_BUFFER_LEN (64)\r
747         byte near_buffer[NEAR_BUFFER_LEN];\r
748         short bio_length,bytes_read,bytes_requested;\r
749 \r
750         bytes_read = 0;\r
751         bio_length = BIO_BUFFER_LEN;\r
752         while (bio_length)\r
753         {\r
754                 if (bio_length > NEAR_BUFFER_LEN-1)\r
755                         bytes_requested = NEAR_BUFFER_LEN;\r
756                 else\r
757                         bytes_requested = bio_length;\r
758 \r
759                 read(bio->handle,near_buffer,bytes_requested);\r
760                 _fmemcpy(MK_FP(bio->buffer,bytes_read),near_buffer,bytes_requested);\r
761 \r
762                 bio_length -= bytes_requested;\r
763                 bytes_read += bytes_requested;\r
764         }\r
765 }\r
766 \r
767 \r
768 #endif\r
769 \r
770 //=========================================================================\r
771 //\r
772 //\r
773 //                                                              GENERAL LOAD ROUTINES\r
774 //\r
775 //\r
776 //=========================================================================\r
777 \r
778 \r
779 \r
780 //--------------------------------------------------------------------------\r
781 // BLoad()\r
782 //--------------------------------------------------------------------------\r
783 unsigned long BLoad(char *SourceFile, memptr *DstPtr)\r
784 {\r
785         int handle;\r
786 \r
787         memptr SrcPtr;\r
788         longword i, j, k, r, c;\r
789         word flags;\r
790         byte Buffer[8];\r
791         longword DstLen, SrcLen;\r
792         boolean comp;\r
793 \r
794         if ((handle = open(SourceFile, O_RDONLY|O_BINARY)) == -1)\r
795                 return(0);\r
796 \r
797         // Look for 'COMP' header\r
798         //\r
799         read(handle,Buffer,4);\r
800         comp = !strncmp(Buffer,COMP,4);\r
801 \r
802         // Get source and destination length.\r
803         //\r
804         if (comp)\r
805         {\r
806                 SrcLen = Verify(SourceFile);\r
807                 read(handle,(void *)&DstLen,4);\r
808                 MM_GetPtr(DstPtr,DstLen);\r
809                 if (!*DstPtr)\r
810                         return(0);\r
811         }\r
812         else\r
813                 DstLen = Verify(SourceFile);\r
814 \r
815         // LZW decompress OR simply load the file.\r
816         //\r
817         if (comp)\r
818         {\r
819 \r
820                 if (MM_TotalFree() < SrcLen)\r
821                 {\r
822                         if (!InitBufferedIO(handle,&lzwBIO))\r
823                                 TrashProg("No memory for buffered I/O.");\r
824                         lzwDecompress(&lzwBIO,MK_FP(*DstPtr,0),SrcLen,(SRC_BFILE|DEST_MEM));\r
825                         FreeBufferedIO(&lzwBIO);\r
826                 }\r
827                 else\r
828                 {\r
829                         CA_LoadFile(SourceFile,&SrcPtr);\r
830                         lzwDecompress(MK_FP(SrcPtr,8),MK_FP(*DstPtr,0),SrcLen,(SRC_MEM|DEST_MEM));\r
831                         MM_FreePtr(&SrcPtr);\r
832                 }\r
833         }\r
834         else\r
835                 CA_LoadFile(SourceFile,DstPtr);\r
836 \r
837         close(handle);\r
838         return(DstLen);\r
839 }\r
840 \r
841 \r
842 \r
843 \r
844 ////////////////////////////////////////////////////////////////////////////\r
845 //\r
846 // LoadLIBShape()\r
847 //\r
848 int LoadLIBShape(char *SLIB_Filename, char *Filename,struct Shape *SHP)\r
849 {\r
850         #define CHUNK(Name)     (*ptr == *Name) &&                      \\r
851                                                                 (*(ptr+1) == *(Name+1)) &&      \\r
852                                                                 (*(ptr+2) == *(Name+2)) &&      \\r
853                                                                 (*(ptr+3) == *(Name+3))\r
854 \r
855 \r
856         int RT_CODE;\r
857         FILE *fp;\r
858         char CHUNK[5];\r
859         char far *ptr;\r
860         memptr IFFfile = NULL;\r
861         unsigned long FileLen, size, ChunkLen;\r
862         int loop;\r
863 \r
864 \r
865         RT_CODE = 1;\r
866 \r
867         // Decompress to ram and return ptr to data and return len of data in\r
868         //      passed variable...\r
869 \r
870         if (!LoadLIBFile(SLIB_Filename,Filename,&IFFfile))\r
871                 TrashProg("Error Loading Compressed lib shape!");\r
872 \r
873         // Evaluate the file\r
874         //\r
875         ptr = MK_FP(IFFfile,0);\r
876         if (!CHUNK("FORM"))\r
877                 goto EXIT_FUNC;\r
878         ptr += 4;\r
879 \r
880         FileLen = *(long far *)ptr;\r
881         SwapLong((long far *)&FileLen);\r
882         ptr += 4;\r
883 \r
884         if (!CHUNK("ILBM"))\r
885                 goto EXIT_FUNC;\r
886         ptr += 4;\r
887 \r
888         FileLen += 4;\r
889         while (FileLen)\r
890         {\r
891                 ChunkLen = *(long far *)(ptr+4);\r
892                 SwapLong((long far *)&ChunkLen);\r
893                 ChunkLen = (ChunkLen+1) & 0xFFFFFFFE;\r
894 \r
895                 if (CHUNK("BMHD"))\r
896                 {\r
897                         ptr += 8;\r
898                         SHP->bmHdr.w = ((struct BitMapHeader far *)ptr)->w;\r
899                         SHP->bmHdr.h = ((struct BitMapHeader far *)ptr)->h;\r
900                         SHP->bmHdr.x = ((struct BitMapHeader far *)ptr)->x;\r
901                         SHP->bmHdr.y = ((struct BitMapHeader far *)ptr)->y;\r
902                         SHP->bmHdr.d = ((struct BitMapHeader far *)ptr)->d;\r
903                         SHP->bmHdr.trans = ((struct BitMapHeader far *)ptr)->trans;\r
904                         SHP->bmHdr.comp = ((struct BitMapHeader far *)ptr)->comp;\r
905                         SHP->bmHdr.pad = ((struct BitMapHeader far *)ptr)->pad;\r
906                         SwapWord(&SHP->bmHdr.w);\r
907                         SwapWord(&SHP->bmHdr.h);\r
908                         SwapWord(&SHP->bmHdr.x);\r
909                         SwapWord(&SHP->bmHdr.y);\r
910                         ptr += ChunkLen;\r
911                 }\r
912                 else\r
913                 if (CHUNK("BODY"))\r
914                 {\r
915                         ptr += 4;\r
916                         size = *((long far *)ptr);\r
917                         ptr += 4;\r
918                         SwapLong((long far *)&size);\r
919                         SHP->BPR = (SHP->bmHdr.w+7) >> 3;\r
920                         MM_GetPtr(&SHP->Data,size);\r
921                         if (!SHP->Data)\r
922                                 goto EXIT_FUNC;\r
923                         movedata(FP_SEG(ptr),FP_OFF(ptr),FP_SEG(SHP->Data),0,size);\r
924                         ptr += ChunkLen;\r
925 \r
926                         break;\r
927                 }\r
928                 else\r
929                         ptr += ChunkLen+8;\r
930 \r
931                 FileLen -= ChunkLen+8;\r
932         }\r
933 \r
934         RT_CODE = 0;\r
935 \r
936 EXIT_FUNC:;\r
937         if (IFFfile)\r
938         {\r
939 //              segptr = (memptr)FP_SEG(IFFfile);\r
940                 MM_FreePtr(&IFFfile);\r
941         }\r
942 \r
943         return (RT_CODE);\r
944 }\r
945 \r
946 \r
947 \r
948 \r
949 \r
950 //----------------------------------------------------------------------------\r
951 // LoadLIBFile() -- Copies a file from an existing archive to dos.\r
952 //\r
953 // PARAMETERS :\r
954 //\r
955 //                      LibName         - Name of lib file created with SoftLib V1.0\r
956 //\r
957 //                      FileName - Name of file to load from lib file.\r
958 //\r
959 //                      MemPtr   - (IF !NULL) - Pointer to memory to load into ..\r
960 //                                                (IF NULL)  - Routine allocates necessary memory and\r
961 //                                                                                      returns a MEM(SEG) pointer to memory allocated.\r
962 //\r
963 // RETURN :\r
964 //\r
965 //              (IF !NULL) - A pointer to the loaded data.\r
966 //                      (IF NULL)  - Error!\r
967 //\r
968 //----------------------------------------------------------------------------\r
969 memptr LoadLIBFile(char *LibName,char *FileName,memptr *MemPtr)\r
970 {\r
971         int handle;\r
972         unsigned long header;\r
973         struct ChunkHeader Header;\r
974         unsigned long ChunkLen;\r
975         short x;\r
976         struct FileEntryHdr FileEntry;                          // Storage for file once found\r
977         struct FileEntryHdr FileEntryHeader;            // Header used durring searching\r
978         struct SoftLibHdr LibraryHeader;                                // Library header - Version Checking\r
979         boolean FileFound = false;\r
980         unsigned long id_slib = ID_SLIB;\r
981         unsigned long id_chunk = ID_CHUNK;\r
982 \r
983 \r
984         //\r
985         // OPEN SOFTLIB FILE\r
986         //\r
987 \r
988         if ((handle = open(LibName,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
989                 return(NULL);\r
990 \r
991 \r
992         //\r
993         //      VERIFY it is a SOFTLIB (SLIB) file\r
994         //\r
995 \r
996         if (read(handle,&header,4) == -1)\r
997         {\r
998                 close(handle);\r
999                 return(NULL);\r
1000         }\r
1001 \r
1002         if (header != id_slib)\r
1003         {\r
1004                 close(handle);\r
1005                 return(NULL);\r
1006         }\r
1007 \r
1008 \r
1009         //\r
1010         // CHECK LIBRARY HEADER VERSION NUMBER\r
1011         //\r
1012 \r
1013         if (read(handle, &LibraryHeader,sizeof(struct SoftLibHdr)) == -1)\r
1014                 TrashProg("read error in LoadSLIBFile()\n%c",7);\r
1015 \r
1016         if (LibraryHeader.Version > SOFTLIB_VER)\r
1017                 TrashProg("Unsupported file ver %d",LibraryHeader.Version);\r
1018 \r
1019 \r
1020         //\r
1021         // MANAGE FILE ENTRY HEADERS...\r
1022         //\r
1023 \r
1024         for (x = 1;x<=LibraryHeader.FileCount;x++)\r
1025         {\r
1026                 if (read(handle, &FileEntryHeader,sizeof(struct FileEntryHdr)) == -1)\r
1027                 {\r
1028                         close(handle);\r
1029                         return(NULL);\r
1030                 }\r
1031 \r
1032                 if (!stricmp(FileEntryHeader.FileName,FileName))\r
1033                 {\r
1034                         FileEntry = FileEntryHeader;\r
1035                         FileFound = true;\r
1036                 }\r
1037         }\r
1038 \r
1039         //\r
1040         // IF FILE HAS BEEN FOUND THEN SEEK TO POSITION AND EXTRACT\r
1041         //      ELSE RETURN WITH ERROR CODE...\r
1042         //\r
1043 \r
1044         if (FileFound)\r
1045         {\r
1046                 if (lseek(handle,FileEntry.Offset,SEEK_CUR) == -1)\r
1047                 {\r
1048                         close(handle);\r
1049                         return(NULL);\r
1050                 }\r
1051 \r
1052                 //\r
1053                 // READ CHUNK HEADER - Verify we are at the beginning of a chunk..\r
1054                 //\r
1055 \r
1056                 if (read(handle,(char *)&Header,sizeof(struct ChunkHeader)) == -1)\r
1057                         TrashProg("LIB File - Unable to read Header!");\r
1058 \r
1059                 if (Header.HeaderID != id_chunk)\r
1060                         TrashProg("LIB File - BAD HeaderID!");\r
1061 \r
1062                 //\r
1063                 // Allocate memory if Necessary...\r
1064                 //\r
1065 \r
1066 \r
1067                 if (!*MemPtr)\r
1068                         MM_GetPtr(MemPtr,FileEntry.OrginalLength);\r
1069 \r
1070                 //\r
1071                 //      Calculate the length of the data (without the chunk header).\r
1072                 //\r
1073 \r
1074                 ChunkLen = FileEntry.ChunkLen - sizeof(struct ChunkHeader);\r
1075 \r
1076 \r
1077                 //\r
1078                 // Extract Data from file\r
1079                 //\r
1080 \r
1081                 switch (Header.Compression)\r
1082                 {\r
1083                         case ct_LZW:\r
1084                                 if (!InitBufferedIO(handle,&lzwBIO))\r
1085                                         TrashProg("No memory for buffered I/O.");\r
1086                                 lzwDecompress(&lzwBIO,MK_FP(*MemPtr,0),ChunkLen,(SRC_BFILE|DEST_MEM));\r
1087                                 FreeBufferedIO(&lzwBIO);\r
1088                                 break;\r
1089 \r
1090                         case ct_NONE:\r
1091                                 if (!CA_FarRead(handle,MK_FP(*MemPtr,0),ChunkLen))\r
1092                                 {\r
1093                                         close(handle);\r
1094                                         *MemPtr = NULL;\r
1095                                 }\r
1096                                 break;\r
1097 \r
1098                         default:\r
1099                                 close(handle);\r
1100                                 TrashProg("Uknown Chunk.Compression Type!");\r
1101                                 break;\r
1102                 }\r
1103         }\r
1104         else\r
1105                 *MemPtr = NULL;\r
1106 \r
1107         close(handle);\r
1108         return(*MemPtr);\r
1109 }\r
1110 \r
1111 \r
1112 \r
1113 \r