1 /* Catacomb Armageddon Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\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
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
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
36 //=========================================================================
\r
39 // LOCAL DEFINATIONS
\r
42 //=========================================================================
\r
44 //#define COMPRESSION_CODE // Comment define in for COMPRESS routines
\r
51 //=========================================================================
\r
57 //=========================================================================
\r
60 unsigned char far LZW_ring_buffer[LZW_N + LZW_F - 1];
\r
62 // ring buffer of size LZW_N, with extra LZW_F-1 bytes to facilitate
\r
63 // string comparison
\r
66 #ifdef COMPRESSION_CODE
\r
71 // MAtchLength of longest match. These are set by the InsertNode()
\r
74 // left & right children & parents -- These constitute binary search trees. */
\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
89 //=========================================================================
\r
92 // COMPRESSION SUPPORT ROUTINES
\r
95 //=========================================================================
\r
98 #ifdef COMPRESSION_CODE
\r
100 //---------------------------------------------------------------------------
\r
102 //---------------------------------------------------------------------------
\r
103 void InitLZWTree(void) /* initialize trees */
\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
115 for (i = LZW_N + 1; i <= LZW_N + 256; i++)
\r
116 LZW_right_child[i] = LZW_NIL;
\r
118 for (i = 0; i < LZW_N; i++)
\r
119 LZW_parent[i] = LZW_NIL;
\r
126 //---------------------------------------------------------------------------
\r
128 //---------------------------------------------------------------------------
\r
129 void InsertLZWNode(unsigned long r)
\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
139 unsigned char *key;
\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
151 if (LZW_right_child[p] != LZW_NIL)
\r
152 p = LZW_right_child[p];
\r
155 LZW_right_child[p] = r;
\r
162 if (LZW_left_child[p] != LZW_NIL)
\r
163 p = LZW_left_child[p];
\r
166 LZW_left_child[p] = r;
\r
172 for (i = 1; i < LZW_F; i++)
\r
173 if ((cmp = key[i] - LZW_ring_buffer[p + i]) != 0)
\r
176 if (i > LZW_match_len)
\r
179 if ((LZW_match_len = i) >= LZW_F)
\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
190 if (LZW_right_child[LZW_parent[p]] == p)
\r
191 LZW_right_child[LZW_parent[p]] = r;
\r
193 LZW_left_child[LZW_parent[p]] = r;
\r
195 LZW_parent[p] = LZW_NIL; /* remove p */
\r
200 //---------------------------------------------------------------------------
\r
202 //---------------------------------------------------------------------------
\r
203 void DeleteLZWNode(unsigned long p) /* deletes node p from tree */
\r
207 if (LZW_parent[p] == LZW_NIL)
\r
208 return; /* not in tree */
\r
210 if (LZW_right_child[p] == LZW_NIL)
\r
211 q = LZW_left_child[p];
\r
213 if (LZW_left_child[p] == LZW_NIL)
\r
214 q = LZW_right_child[p];
\r
217 q = LZW_left_child[p];
\r
218 if (LZW_right_child[q] != LZW_NIL)
\r
222 q = LZW_right_child[q];
\r
224 } while (LZW_right_child[q] != LZW_NIL);
\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
232 LZW_right_child[q] = LZW_right_child[p];
\r
233 LZW_parent[LZW_right_child[p]] = q;
\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
240 LZW_left_child[LZW_parent[p]] = q;
\r
242 LZW_parent[p] = LZW_NIL;
\r
249 //=========================================================================
\r
252 // GENERAL FILE to FILE compression routines
\r
254 // * Mainly for example usage of PTR/PTR (de)compression routines.
\r
257 //=========================================================================
\r
261 //////////////////////////////////////////////////////////////////////
\r
263 // CompressFILEtoFILE() -- Compresses one file stream to another file stream
\r
266 #ifdef COMPRESSION_CODE
\r
268 unsigned long CompressFILEtoFILE(FILE *infile, FILE *outfile,unsigned long DataLength)
\r
270 unsigned long returnval;
\r
272 fwrite(COMP,4,1,outfile);
\r
273 fwrite((char *)&DataLength,4,1,outfile);
\r
275 returnval = 8+lzwCompress(infile,outfile,DataLength,(SRC_FFILE|DEST_FFILE));
\r
283 /////////////////////////////////////////////////////////////////////////////
\r
285 // DecompressFILEtoFILE()
\r
287 void DecompressFILEtoFILE(FILE *infile, FILE *outfile)
\r
289 unsigned char Buffer[8];
\r
290 unsigned long DataLength;
\r
292 fread(Buffer,1,4,infile);
\r
294 if (strncmp(Buffer,COMP,4))
\r
296 printf("\nNot a JAM Compressed File!\n");
\r
300 fread((void *)&DataLength,1,4,infile);
\r
302 lzwDecompress(infile,outfile,DataLength,(SRC_FFILE|DEST_FFILE));
\r
310 //==========================================================================
\r
313 // WRITE/READ PTR ROUTINES
\r
316 //==========================================================================
\r
320 //---------------------------------------------------------------------------
\r
321 // WritePtr() -- Outputs data to a particular ptr type
\r
323 // PtrType MUST be of type DEST_TYPE.
\r
325 // NOTE : For PtrTypes DEST_MEM a ZERO (0) is always returned.
\r
327 //---------------------------------------------------------------------------
\r
328 int WritePtr(long outfile, unsigned char data, unsigned PtrType)
\r
332 switch (PtrType & DEST_TYPES)
\r
335 write(*(int far *)outfile,(char *)&data,1);
\r
339 returnval = putc(data, *(FILE **)outfile);
\r
343 // *(*(char far **)outfile++) = data; // Do NOT delete
\r
344 *((char far *)*(char far **)outfile)++ = data;
\r
348 TrashProg("WritePtr() : Unknown DEST_PTR type");
\r
357 //---------------------------------------------------------------------------
\r
358 // ReadPtr() -- Reads data from a particular ptr type
\r
360 // PtrType MUST be of type SRC_TYPE.
\r
363 // The char read in or EOF for SRC_FFILE type of reads.
\r
366 //---------------------------------------------------------------------------
\r
367 int ReadPtr(long infile, unsigned PtrType)
\r
371 switch (PtrType & SRC_TYPES)
\r
374 read(*(int far *)infile,(char *)&returnval,1);
\r
378 // JIM - JTR - is the following correct? "fgetc()" uses a near pointer.
\r
380 returnval = fgetc((FILE far *)*(FILE far **)infile);
\r
384 returnval = bio_readch((BufferedIO *)*(void far **)infile);
\r
388 returnval = (char)*(*(char far **)infile++);
\r
389 // returnval = *((char far *)*(char far **)infile)++; // DO NOT DELETE!
\r
393 TrashProg("ReadPtr() : Unknown SRC_PTR type");
\r
403 //=========================================================================
\r
406 // COMPRESSION & DECOMPRESSION ROUTINES
\r
409 //=========================================================================
\r
412 //--------------------------------------------------------------------------
\r
414 // lzwCompress() - Compresses data from an input ptr to a dest ptr
\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
423 // Length of compressed data.
\r
425 // COMPTYPE : ct_LZW
\r
427 // NOTES : Does not write ANY header information!
\r
429 #ifdef COMPRESSION_CODE
\r
430 unsigned long lzwCompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)
\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
437 // initialize trees
\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
450 code_buf_ptr = mask = 1;
\r
454 // Clear the buffer with any character that will appear often.
\r
457 for (i = s; i < r; i++)
\r
458 LZW_ring_buffer[i] = ' ';
\r
460 // Read LZW_F bytes into the last LZW_F bytes of the buffer
\r
463 for (len = 0; (len < LZW_F) && DataLength; len++)
\r
465 c = ReadPtr((long)&infile,PtrTypes);
\r
468 // text of size zero
\r
470 LZW_ring_buffer[r + len] = c;
\r
473 if (!(len && DataLength))
\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
483 for (i = 1; i <= LZW_F; i++)
\r
484 InsertLZWNode(r - i);
\r
487 // Finally, insert the whole string just read. The global
\r
488 // variables LZW_match_len and LZW_match_pos are set. */
\r
494 // LZW_match_len may be spuriously long near the end of text.
\r
497 if (LZW_match_len > len)
\r
498 LZW_match_len = len;
\r
500 if (LZW_match_len <= LZW_THRESHOLD)
\r
502 // Not long enough match. Send one byte.
\r
507 // 'send one byte' flag
\r
510 code_buf[0] |= mask;
\r
515 code_buf[code_buf_ptr++] = LZW_ring_buffer[r];
\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
522 // Send position and length pair.
\r
523 // Note LZW_match_len > LZW_THRESHOLD.
\r
526 if ((mask <<= 1) == 0)
\r
528 // Shift mask left one bit.
\r
529 // Send at most 8 units of data
\r
531 for (i = 0; i < code_buf_ptr; i++)
\r
532 WritePtr((long)&outfile,code_buf[i],PtrTypes);
\r
534 complen += code_buf_ptr;
\r
536 code_buf_ptr = mask = 1;
\r
539 last_LZW_match_len = LZW_match_len;
\r
541 for (i = 0; i < last_LZW_match_len && DataLength; i++)
\r
543 c = ReadPtr((long)&infile,PtrTypes);
\r
546 DeleteLZWNode(s); // Delete old strings and
\r
547 LZW_ring_buffer[s] = c; // read new bytes
\r
549 // If the position is near the end of buffer, extend the
\r
550 // buffer to make string comparison easier.
\r
553 LZW_ring_buffer[s + LZW_N] = c;
\r
555 // Since this is a ring buffer, inc the position modulo LZW_N.
\r
558 s = (s + 1) & (LZW_N - 1);
\r
559 r = (r + 1) & (LZW_N - 1);
\r
561 // Register the string in LZW_ring_buffer[r..r+LZW_F-1]
\r
567 while (i++ < last_LZW_match_len)
\r
569 // After the end of text,
\r
570 DeleteLZWNode(s); // no need to read, but
\r
572 s = (s + 1) & (LZW_N - 1);
\r
573 r = (r + 1) & (LZW_N - 1);
\r
576 InsertLZWNode(r); // buffer may not be empty.
\r
579 } while (len > 0); // until length of string to be processed is zero
\r
582 if (code_buf_ptr > 1)
\r
584 // Send remaining code.
\r
587 for (i = 0; i < code_buf_ptr; i++)
\r
588 WritePtr((long)&outfile,code_buf[i],PtrTypes);
\r
590 complen += code_buf_ptr;
\r
600 //--------------------------------------------------------------------------
\r
602 // lzwDecompress() - Compresses data from an input ptr to a dest ptr
\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
611 // Length of compressed data.
\r
613 // COMPTYPE : ct_LZW
\r
615 // NOTES : Does not write ANY header information!
\r
617 void far lzwDecompress(void far *infile, void far *outfile,unsigned long DataLength,unsigned PtrTypes)
\r
620 unsigned int flags;
\r
622 for (i = 0; i < LZW_N - LZW_F; i++)
\r
623 LZW_ring_buffer[i] = ' ';
\r
630 if (((flags >>= 1) & 256) == 0)
\r
632 c = ReadPtr((long)&infile,PtrTypes);
\r
636 flags = c | 0xff00; // uses higher byte cleverly to count 8
\r
641 c = ReadPtr((long)&infile,PtrTypes); // Could test for EOF iff FFILE type
\r
645 WritePtr((long)&outfile,c,PtrTypes);
\r
647 LZW_ring_buffer[r++] = c;
\r
652 i = ReadPtr((long)&infile,PtrTypes);
\r
656 j = ReadPtr((long)&infile,PtrTypes);
\r
660 i |= ((j & 0xf0) << 4);
\r
661 j = (j & 0x0f) + LZW_THRESHOLD;
\r
663 for (k = 0; k <= j; k++)
\r
665 c = LZW_ring_buffer[(i + k) & (LZW_N - 1)];
\r
667 WritePtr((long)&outfile,c,PtrTypes);
\r
669 LZW_ring_buffer[r++] = c;
\r
679 //=========================================================================
\r
682 // BUFFERED I/O ROUTINES
\r
685 //=========================================================================
\r
688 //--------------------------------------------------------------------------
\r
689 // InitBufferedIO()
\r
690 //--------------------------------------------------------------------------
\r
691 memptr InitBufferedIO(int handle, BufferedIO *bio)
\r
693 bio->handle = handle;
\r
694 bio->offset = BIO_BUFFER_LEN;
\r
696 MM_GetPtr(&bio->buffer,BIO_BUFFER_LEN);
\r
698 return(bio->buffer);
\r
702 //--------------------------------------------------------------------------
\r
703 // FreeBufferedIO()
\r
704 //--------------------------------------------------------------------------
\r
705 void FreeBufferedIO(BufferedIO *bio)
\r
708 MM_FreePtr(&bio->buffer);
\r
712 //--------------------------------------------------------------------------
\r
714 //--------------------------------------------------------------------------
\r
715 byte bio_readch(BufferedIO *bio)
\r
719 if (bio->offset == BIO_BUFFER_LEN)
\r
722 bio_fillbuffer(bio);
\r
725 buffer = MK_FP(bio->buffer,bio->offset++);
\r
731 //--------------------------------------------------------------------------
\r
732 // bio_fillbuffer()
\r
734 // BUGS (Not really bugs... More like RULES!)
\r
736 // 1) This code assumes BIO_BUFFER_LEN is no smaller than
\r
737 // NEAR_BUFFER_LEN!!
\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
743 //--------------------------------------------------------------------------
\r
744 void bio_fillbuffer(BufferedIO *bio)
\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
751 bio_length = BIO_BUFFER_LEN;
\r
754 if (bio_length > NEAR_BUFFER_LEN-1)
\r
755 bytes_requested = NEAR_BUFFER_LEN;
\r
757 bytes_requested = bio_length;
\r
759 read(bio->handle,near_buffer,bytes_requested);
\r
760 _fmemcpy(MK_FP(bio->buffer,bytes_read),near_buffer,bytes_requested);
\r
762 bio_length -= bytes_requested;
\r
763 bytes_read += bytes_requested;
\r
770 //=========================================================================
\r
773 // GENERAL LOAD ROUTINES
\r
776 //=========================================================================
\r
780 //--------------------------------------------------------------------------
\r
782 //--------------------------------------------------------------------------
\r
783 unsigned long BLoad(char *SourceFile, memptr *DstPtr)
\r
788 longword i, j, k, r, c;
\r
791 longword DstLen, SrcLen;
\r
794 if ((handle = open(SourceFile, O_RDONLY|O_BINARY)) == -1)
\r
797 // Look for 'COMP' header
\r
799 read(handle,Buffer,4);
\r
800 comp = !strncmp(Buffer,COMP,4);
\r
802 // Get source and destination length.
\r
806 SrcLen = Verify(SourceFile);
\r
807 read(handle,(void *)&DstLen,4);
\r
808 MM_GetPtr(DstPtr,DstLen);
\r
813 DstLen = Verify(SourceFile);
\r
815 // LZW decompress OR simply load the file.
\r
820 if (MM_TotalFree() < SrcLen)
\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
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
835 CA_LoadFile(SourceFile,DstPtr);
\r
844 ////////////////////////////////////////////////////////////////////////////
\r
848 int LoadLIBShape(char *SLIB_Filename, char *Filename,struct Shape *SHP)
\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
860 memptr IFFfile = NULL;
\r
861 unsigned long FileLen, size, ChunkLen;
\r
867 // Decompress to ram and return ptr to data and return len of data in
\r
868 // passed variable...
\r
870 if (!LoadLIBFile(SLIB_Filename,Filename,&IFFfile))
\r
871 TrashProg("Error Loading Compressed lib shape!");
\r
873 // Evaluate the file
\r
875 ptr = MK_FP(IFFfile,0);
\r
876 if (!CHUNK("FORM"))
\r
880 FileLen = *(long far *)ptr;
\r
881 SwapLong((long far *)&FileLen);
\r
884 if (!CHUNK("ILBM"))
\r
891 ChunkLen = *(long far *)(ptr+4);
\r
892 SwapLong((long far *)&ChunkLen);
\r
893 ChunkLen = (ChunkLen+1) & 0xFFFFFFFE;
\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
916 size = *((long far *)ptr);
\r
918 SwapLong((long far *)&size);
\r
919 SHP->BPR = (SHP->bmHdr.w+7) >> 3;
\r
920 MM_GetPtr(&SHP->Data,size);
\r
923 movedata(FP_SEG(ptr),FP_OFF(ptr),FP_SEG(SHP->Data),0,size);
\r
931 FileLen -= ChunkLen+8;
\r
939 // segptr = (memptr)FP_SEG(IFFfile);
\r
940 MM_FreePtr(&IFFfile);
\r
950 //----------------------------------------------------------------------------
\r
951 // LoadLIBFile() -- Copies a file from an existing archive to dos.
\r
955 // LibName - Name of lib file created with SoftLib V1.0
\r
957 // FileName - Name of file to load from lib file.
\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
965 // (IF !NULL) - A pointer to the loaded data.
\r
966 // (IF NULL) - Error!
\r
968 //----------------------------------------------------------------------------
\r
969 memptr LoadLIBFile(char *LibName,char *FileName,memptr *MemPtr)
\r
972 unsigned long header;
\r
973 struct ChunkHeader Header;
\r
974 unsigned long ChunkLen;
\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
985 // OPEN SOFTLIB FILE
\r
988 if ((handle = open(LibName,O_RDONLY | O_BINARY, S_IREAD)) == -1)
\r
993 // VERIFY it is a SOFTLIB (SLIB) file
\r
996 if (read(handle,&header,4) == -1)
\r
1002 if (header != id_slib)
\r
1010 // CHECK LIBRARY HEADER VERSION NUMBER
\r
1013 if (read(handle, &LibraryHeader,sizeof(struct SoftLibHdr)) == -1)
\r
1014 TrashProg("read error in LoadSLIBFile()\n%c",7);
\r
1016 if (LibraryHeader.Version > SOFTLIB_VER)
\r
1017 TrashProg("Unsupported file ver %d",LibraryHeader.Version);
\r
1021 // MANAGE FILE ENTRY HEADERS...
\r
1024 for (x = 1;x<=LibraryHeader.FileCount;x++)
\r
1026 if (read(handle, &FileEntryHeader,sizeof(struct FileEntryHdr)) == -1)
\r
1032 if (!stricmp(FileEntryHeader.FileName,FileName))
\r
1034 FileEntry = FileEntryHeader;
\r
1040 // IF FILE HAS BEEN FOUND THEN SEEK TO POSITION AND EXTRACT
\r
1041 // ELSE RETURN WITH ERROR CODE...
\r
1046 if (lseek(handle,FileEntry.Offset,SEEK_CUR) == -1)
\r
1053 // READ CHUNK HEADER - Verify we are at the beginning of a chunk..
\r
1056 if (read(handle,(char *)&Header,sizeof(struct ChunkHeader)) == -1)
\r
1057 TrashProg("LIB File - Unable to read Header!");
\r
1059 if (Header.HeaderID != id_chunk)
\r
1060 TrashProg("LIB File - BAD HeaderID!");
\r
1063 // Allocate memory if Necessary...
\r
1068 MM_GetPtr(MemPtr,FileEntry.OrginalLength);
\r
1071 // Calculate the length of the data (without the chunk header).
\r
1074 ChunkLen = FileEntry.ChunkLen - sizeof(struct ChunkHeader);
\r
1078 // Extract Data from file
\r
1081 switch (Header.Compression)
\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
1091 if (!CA_FarRead(handle,MK_FP(*MemPtr,0),ChunkLen))
\r
1100 TrashProg("Uknown Chunk.Compression Type!");
\r