1 /*****
2 * LZWStream.c : LZW uncompressor that doesn't use the LZW algorithm but
3 * converts LZW compressed data to compress LZW data and
4 * calls compress to do the uncompressing.
5 *
6 * This file Version $Revision: 1.6 $
7 *
8 * Creation date: Thu May 8 04:53:42 GMT+0100 1997
9 * Last modification: $Date: 1998/04/27 06:55:01 $
10 * By: $Author: newt $
11 * Current State: $State: Exp $
12 *
13 * Author: newt
14 *
15 * Copyright (C) 1994-1997 by Ripley Software Development
16 * All Rights Reserved
17 *
18 * This file is part of the XmHTML Widget Library.
19 *
20 * Permission to use, copy, modify, and distribute this software and its
21 * documentation for any purpose and without fee is hereby granted, provided
22 * that the above copyright notice appear in all copies and that both that
23 * copyright notice and this permission notice appear in supporting
24 * documentation. This software is provided "as is" without express or
25 * implied warranty.
26 *
27 * Based on an idea from Derek D. Noonburg <derekn@ece.cmu.edu>, author of
28 * the public domain xpdf package, a PDF viewer.
29 *
30 *****/
31 /*****
32 * ChangeLog
33 * $Log: LZWStream.c,v $
34 * Revision 1.6 1998/04/27 06:55:01 newt
35 * tka stuff
36 *
37 * Revision 1.5 1998/04/04 06:27:47 newt
38 * XmHTML Beta 1.1.3
39 *
40 * Revision 1.4 1997/10/23 00:24:33 newt
41 * XmHTML Beta 1.1.0 release
42 *
43 * Revision 1.3 1997/08/30 00:23:48 newt
44 * Removed XmHTML dependencies.
45 *
46 * Revision 1.2 1997/08/01 12:52:18 newt
47 * Progressive image loading changes
48 *
49 * Revision 1.1 1997/05/28 01:27:00 newt
50 * Initial Revision
51 *
52 *****/
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #ifndef WINNT
61 #include <unistd.h>
62 #endif
63
64 #ifndef NO_XmHTML /* defined when compiling for standalone */
65 #include "toolkit.h"
66 #include XmHTMLPrivateHeader
67 #else
68 #include "ImBuffer.h" /* ImageBuffer stuff */
69 typedef unsigned char Boolean;
70 #define True 1
71 #define False 0
72 #endif
73
74 #include <LZWStream.h>
75
76 /*** External Function Prototype Declarations ***/
77
78 /*** Public Variable Declarations ***/
79 #ifdef DEBUG
80 int lzw_debug = False;
81 #endif
82
83 /*** Private Datatype Declarations ****/
84
85 #define INIT_BITS 9 /* minimum compress codeSize */
86 #define MAX_LZW_BITS 12 /* maximum GIF LZW codeSize */
87 #define MAX_BITS 13 /* maximum compress codeSize */
88 #define MAX_LZW_CODE (1<<MAX_LZW_BITS) /* maximum code GIF signal value */
89 #define MAX_CODE (1<<MAX_BITS) /* maximum code signal value */
90 #define FIRST 257 /* first free slot in compress */
91 #define CLEAR 256 /* compress clearcode signal */
92
93 /****
94 * Note: we set the maximum bits available for compress to 13 instead of 12.
95 * This ensures that the compress code storage keeps in sync with the GIF LZW
96 * codes when the gif code size is less than 8. Using 12 bits for compress
97 * would overflow the compress tables before the GIF clearCode signal is
98 * received.
99 ****/
100
101 /*** Private Function Prototype Declarations ****/
102 static int LZWStreamUncompressData(LZWStream *lzw);
103 static void LZWStreamPackBits(LZWStream *lzw, int code);
104 static void LZWStreamConvertBelow8(LZWStream *lzw);
105 static void LZWStreamConvert8OrAbove(LZWStream *lzw);
106
107 /****
108 * Two macros for buffered output; reduces the no of function calls.
109 * BUFFERSIZE determines the size of the output buffer and is defined in
110 * LZWStream.h (default is 512).
111 ****/
112 /* flush output buffer if it contains something */
113 #define flushBuf { if(lzw->acount > 0) \
114 { \
115 fwrite(lzw->accum, (size_t)1, (size_t)lzw->acount, lzw->f); \
116 lzw->acount = 0; \
117 } \
118 }
119
120 /* buffer output and flush when full */
121 #define charOut(C) { lzw->accum[lzw->acount++] = (unsigned char)C; \
122 if(lzw->acount >= BUFFERSIZE-1) \
123 flushBuf; \
124 }
125
126 #define MAXCODE(n_bits) ((1L << (n_bits)) - 1)
127
128 /*** Private Variable Declarations ***/
129 #ifdef DEBUG
130 static int bytes_out;
131 #endif
132
133 static char msg_buf[1024];
134 static char *err_str = "LZWStream Error: ";
135
136 /* bit packing masks */
137 static Byte lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
138 static Byte rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
139
140 /*****
141 * Name: LZWStreamGetCode MACRO
142 * Return Type: N/A
143 * Description: gets next code signal from the LZW stream
144 * In:
145 * lzw: current LZWStream
146 * code: value to update
147 * Returns:
148 * N/A
149 * Note:
150 * This is a macro instead of a function, since this is used for every
151 * byte of data...
152 *****/
153 #define LZWStreamGetCode(lzw,code) do { \
154 register int i, j; \
155 code = 0; \
156 if(lzw->error) \
157 { \
158 lzw->error = 0; \
159 code = lzw->clearCode; \
160 } \
161 else \
162 { \
163 if((lzw->curBit + lzw->codeBits) >= lzw->lastBit) \
164 { \
165 int count; \
166 if(lzw->done) \
167 code = -1; \
168 else \
169 { \
170 lzw->buf[0] = (int)((Byte)lzw->buf[lzw->lastByte-2]); \
171 lzw->buf[1] = (int)((Byte)lzw->buf[lzw->lastByte-1]); \
172 if((count = (int)lzw->getData(lzw->ib, \
173 (Byte*)&(lzw->buf[2]))) == 0) \
174 lzw->done = 1; \
175 lzw->lastByte = 2 + count; \
176 lzw->curBit = (lzw->curBit - lzw->lastBit) + 16; \
177 lzw->lastBit = (2+count)*8 ; \
178 } \
179 } \
180 if(code == 0) \
181 for(i = lzw->curBit, j = 0; j < lzw->codeBits; ++i, ++j) \
182 code |= (((int)((Byte)lzw->buf[i/8]) & (1<<(i%8)))!= 0)<<j; \
183 lzw->curBit += lzw->codeBits; \
184 } \
185 }while(0)
186
187 /*****
188 * Name: LZWStreamUncompressData
189 * Return Type: int
190 * Description: calls "uncompress" to uncompress the LZW-compressed GIF raster
191 * data
192 * In:
193 * lzw: current LZWStream
194 * Returns:
195 * True upon success, False on error.
196 *****/
197 static int
LZWStreamUncompressData(LZWStream * lzw)198 LZWStreamUncompressData(LZWStream *lzw)
199 {
200 /* no error */
201 lzw->err_msg = NULL;
202
203 if(lzw->zPipe == NULL)
204 {
205 /* flush output file */
206 fflush(lzw->f);
207
208 /* call uncompress on our converted GIF lzw data */
209 if(system(lzw->zCmd))
210 {
211 sprintf(msg_buf, "%sCouldn't exec '%s'.", err_str,
212 lzw->zCmd);
213 lzw->err_msg = msg_buf;
214 unlink(lzw->zName);
215 lzw->error = True;
216 return(False);
217 }
218 /* open the output file */
219 lzw->zName[strlen(lzw->zName) - 2] = '\0';
220 if((lzw->zPipe = fopen(lzw->zName, "r")) == NULL)
221 {
222 sprintf(msg_buf, "%sCouldn't open uncompress file '%s'. "
223 "Corrupt data?", err_str, lzw->zName);
224 lzw->err_msg = msg_buf;
225 unlink(lzw->zName);
226 lzw->error = True;
227 return(False);
228 }
229 }
230 lzw->uncompressed = True;
231 return(True);
232 }
233
234 /*****
235 * Name: LZWStreamPackBits
236 * Return Type: void
237 * Description: buffers LZW codes and writes them out when the buffer is full.
238 * In:
239 * lzw: current LZWStream
240 * code: LZW code to be written.
241 * Returns:
242 * nothing
243 * Note:
244 * This routine is for gif images with less than 8 bits per pixel (= codeSize)
245 * and packs the LZW codes the same way compress does. This is ABSOLUTELY
246 * REQUIRED since compress only deals with codes between 8 and 15 bits.
247 * This piece of code has been lifted almost literally from the public domain
248 * compress.
249 *****/
250 static void
LZWStreamPackBits(LZWStream * lzw,int code)251 LZWStreamPackBits(LZWStream *lzw, int code)
252 {
253 register int r_off = lzw->offset; /* current offset in output buffer */
254 register int bits = lzw->n_bits; /* bits per pixel */
255 register char *bp = lzw->outBuf; /* ptr to current pos in buffer */
256
257 #ifdef DEBUG
258 static int col = 0;
259 if(lzw_debug == 2)
260 fprintf(stderr, "%5d%c", code,
261 (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
262 #endif /* DEBUG */
263
264 if(code >= 0)
265 {
266 /* Get to the first byte. */
267 bp += (r_off >> 3);
268 r_off &= 7;
269 /*
270 * Since code is always >= 8 bits, only need to mask the first
271 * hunk on the left.
272 */
273 *bp = (*bp & rmask[r_off]) | ((code << r_off) & lmask[r_off]);
274 bp++;
275 bits -= (8 - r_off);
276 code >>= 8 - r_off;
277
278 /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
279 if(bits >= 8)
280 {
281 *bp++ = code;
282 code >>= 8;
283 bits -= 8;
284 }
285 /* Last bits. */
286 if(bits)
287 *bp = code;
288
289 lzw->offset += lzw->n_bits;
290 if(lzw->offset == (lzw->n_bits << 3))
291 {
292 bp = lzw->outBuf;
293 bits = lzw->n_bits;
294 #ifdef DEBUG
295 bytes_out += bits;
296 #endif
297 do
298 {
299 charOut(*bp++);
300 }
301 while(--bits);
302 lzw->offset = 0;
303 }
304
305 /*
306 * If the next entry is going to be too big for the code size,
307 * then increase it, if possible.
308 */
309 if(lzw->freeEntry > lzw->maxcode8 || lzw->clearFlag)
310 {
311 /* flush contents of output buffer */
312 flushBuf;
313
314 /*
315 * Write the whole buffer, because the input side won't
316 * discover the size increase until after it has read it.
317 */
318 if(lzw->offset > 0)
319 {
320 fwrite(lzw->outBuf, 1, lzw->n_bits, lzw->f);
321 #ifdef DEBUG
322 bytes_out += lzw->n_bits;
323 #endif
324 }
325 lzw->offset = 0;
326
327 if(lzw->clearFlag)
328 {
329 lzw->maxcode8 = MAXCODE(lzw->n_bits = INIT_BITS);
330 lzw->clearFlag = False;
331 }
332 else
333 {
334 lzw->n_bits++;
335 if (lzw->n_bits == MAX_BITS)
336 lzw->maxcode8 = MAX_CODE;
337 else
338 lzw->maxcode8 = MAXCODE(lzw->n_bits);
339 }
340 #ifdef DEBUG
341 if(lzw_debug == 2)
342 {
343 fprintf(stderr, "\nChange to %d bits\n", lzw->n_bits );
344 col = 0;
345 }
346 #endif /* DEBUG */
347 }
348 }
349 /* flush rest of buffer at EOF */
350 else
351 {
352 /* flush contents of output buffer */
353 flushBuf;
354
355 #ifdef DEBUG
356 if(lzw_debug == 2)
357 fprintf(stderr, "\n" );
358 #endif /* DEBUG */
359 if(lzw->offset > 0)
360 {
361 /* flush out remaining chars */
362 fwrite(lzw->outBuf, 1, (lzw->offset+7)/8, lzw->f);
363
364 #ifdef DEBUG
365 bytes_out += (lzw->offset + 7)/8;
366 #endif
367 lzw->offset = 0;
368 fflush(lzw->f);
369 }
370 }
371 }
372
373 /*****
374 * Name: LZWStreamConvertBelow8
375 * Return Type: void
376 * Description: converts the GIF LZW compressed raster data to the compress
377 * compressed data format. codeSize < 8
378 * In:
379 * lzw: current LZWStream object
380 * Returns:
381 * nothing
382 *****/
383 static void
LZWStreamConvertBelow8(LZWStream * lzw)384 LZWStreamConvertBelow8(LZWStream *lzw)
385 {
386 int inCode; /* input code */
387 Boolean eod = False; /* set when end-of-data is reached */
388 Boolean first; /* indicates first code word after clear */
389 int offset;
390
391 #ifdef DEBUG
392 bytes_out = 3; /* includes 3-byte header mojo */
393 #endif
394
395 /* clear table */
396 first = True;
397 offset = 255 - lzw->clearCode;
398 lzw->error = True; /* skips first clearCode in raster data */
399 lzw->nextCode = lzw->maxCode;
400 lzw->freeEntry = FIRST;
401
402 /*
403 * mimic compress behaviour but get LZW code instead of computing it.
404 * GIF LZW code needs to be corrected to match fixed compress codes so we
405 * can properly reset the tables if required. We also must keep track of
406 * the LZW codesize since it influences the values of the LZW codes.
407 */
408 while(!eod)
409 {
410 LZWStreamGetCode(lzw,inCode);
411 if(inCode == -1)
412 break;
413 /*****
414 * First part: verify and adjust GIF LZW code signal.
415 *****/
416
417 /*
418 * clearCode sets everything back to their initial values and then
419 * reads the next code.
420 */
421 if(inCode == lzw->clearCode)
422 {
423 /* reset code table */
424 lzw->codeBits = lzw->codeSize + 1;
425 lzw->clearCode = 1 << lzw->codeSize;
426 lzw->endCode = lzw->clearCode + 1;
427 lzw->maxCodeSize = 2*lzw->clearCode;
428 lzw->maxCode = lzw->clearCode + 2;
429 lzw->nextCode = lzw->maxCode - 1;
430 offset = 255 - lzw->clearCode;
431
432 /* keep output side in sync */
433 if(first)
434 first = False;
435 else
436 {
437 lzw->freeEntry = FIRST;
438 lzw->clearFlag = True;
439 LZWStreamPackBits(lzw, CLEAR);
440 #ifdef DEBUG
441 if(lzw_debug == 2)
442 fprintf(stderr, "clear\n");
443 #endif /* DEBUG */
444 }
445 /* get next code */
446 do
447 {
448 LZWStreamGetCode(lzw, inCode);
449 if (inCode == -1)
450 {
451 /* end-of-data, break out of it */
452 eod = True;
453 inCode = lzw->endCode;
454 break;
455 }
456 }while(inCode == lzw->clearCode);
457 }
458
459 /* End-of-data, compress doesn't have this , so just break */
460 if(inCode == lzw->endCode)
461 {
462 eod = True;
463 break;
464 }
465 /*
466 * Check input code size and adjust if the next code would overflow
467 * the LZW tables. Compressed GIF raster data uses a range starting
468 * at codeSize + 1 up to 12 bits per code.
469 */
470 if((++lzw->nextCode >= lzw->maxCodeSize) &&
471 (lzw->maxCodeSize < MAX_LZW_CODE))
472 {
473 lzw->maxCodeSize *= 2;
474 lzw->codeBits++;
475 }
476
477 /*****
478 * Second part: write corrected LZW code
479 *
480 * write output block: the output buffer contains a series of bytes
481 * with lengths anywhere between 3 and 12. Compress can only handle
482 * codeSize 8 or up, anything below must be packed according to the
483 * format compress expects.
484 * This was the most difficult part to figure out, but its as simple
485 * as this: the GIF lzw codes are just increased with the difference
486 * of compress clearCode (fixed value of 256) and the current GIF
487 * clearCode...
488 *****/
489
490 /* correct and flush */
491 LZWStreamPackBits(lzw,
492 inCode < lzw->clearCode ? inCode : inCode + offset);
493
494 if(lzw->freeEntry < MAX_CODE)
495 lzw->freeEntry++;
496 }
497 /* flush output buffer */
498 LZWStreamPackBits(lzw, -1);
499
500 /* and close output file */
501 fflush(lzw->f);
502 fclose(lzw->f);
503 lzw->f = NULL;
504 }
505
506 /*****
507 * Name: LZWStreamConvert8OrAbove
508 * Return Type: void
509 * Description: converts the GIF LZW compressed raster data to the compress
510 * compressed data format. codeSize >= 8
511 * In:
512 * lzw: current LZWStream object
513 * Returns:
514 * nothing
515 *****/
516 static void
LZWStreamConvert8OrAbove(LZWStream * lzw)517 LZWStreamConvert8OrAbove(LZWStream *lzw)
518 {
519 int outBuf[8];
520 int inCode, outCode; /* input and output codes */
521 int outCodeBits; /* size of output code */
522 int maxOutSize; /* maximum output signal */
523 Boolean eod = False; /* set when end-of-data is reached */
524 Boolean clear; /* set if table needs to be cleared */
525 Boolean first; /* indicates first code word after clear */
526 int i, j;
527 int outData, outBits;
528
529 #ifdef DEBUG
530 bytes_out = 3; /* includes 3-byte header mojo */
531 #endif
532
533 /* init output side */
534 outCodeBits = lzw->codeBits;
535 maxOutSize = 2*lzw->clearCode;
536
537 /* clear table */
538 first = True;
539 lzw->error = True; /* skips first clearCode in raster data */
540 lzw->nextCode = lzw->maxCode - 1;
541 clear = False;
542
543 do
544 {
545 /* create output buffer */
546 for (i = 0; i < 8; ++i)
547 {
548 /* check for table overflow */
549 if(lzw->nextCode + 1 > 0x1001)
550 {
551 /* clear string table */
552 inCode = 256;
553 }
554 /* read input code */
555 else
556 {
557 do
558 {
559 LZWStreamGetCode(lzw, inCode);
560 if (inCode == -1)
561 {
562 eod = True;
563 inCode = 0;
564 }
565 }while (first && inCode == lzw->clearCode);
566 first = False;
567 }
568
569 /*
570 * code signal less than clear code signal: compressed data,
571 * store it.
572 */
573 if (inCode < lzw->clearCode)
574 {
575 outCode = inCode;
576 }
577 /*
578 * code signal equals clear code. Set flag so string table will
579 * be cleared. GIF clearCode signal value is dynamic, whereas
580 * compress uses a fixed value of 256.
581 */
582 else if (inCode == lzw->clearCode)
583 {
584 outCode = 256;
585 clear = True;
586 first = False;
587 }
588 /*
589 * end code signal. Compress does not have this signal so just set
590 * the end-of-data flag.
591 */
592 else if (inCode == lzw->endCode)
593 {
594 outCode = 0;
595 eod = True;
596 }
597 else
598 /*
599 * code signal higher than end code signal: compressed data,
600 * store it.
601 */
602 outCode = inCode - 1;
603
604 outBuf[i] = outCode;
605
606 /*
607 * check input code size. Compressed GIF raster data uses a range
608 * starting at codeSize + 1 up to 12 bits per code.
609 */
610 if((++lzw->nextCode >= lzw->maxCodeSize) &&
611 (lzw->maxCodeSize < MAX_LZW_CODE))
612 {
613 lzw->maxCodeSize *= 2;
614 ++lzw->codeBits;
615 }
616
617 /* check for eod/clear */
618 if (eod)
619 {
620 break;
621 }
622 if(clear)
623 {
624 i = 8;
625 break;
626 }
627 }
628
629 /*
630 * write output block: the output buffer contains a series of bytes
631 * with lengths anywhere between 8 and 12. The output buffer is just
632 * packed in the same way an LZW gif *writer* does it.
633 */
634 outBits = 0; /* max output code */
635 outData = 0; /* temporary output buffer */
636 j = 0;
637 while(j < i || outBits > 0)
638 {
639 /* package all codes */
640 if(outBits < 8 && j < i)
641 {
642 outData = outData | (outBuf[j++] << outBits);
643 outBits += outCodeBits;
644 }
645 charOut(outData & 0xff);
646 outData >>= 8;
647 outBits -= 8;
648 }
649
650 #ifdef DEBUG
651 bytes_out += outCodeBits;
652 #endif
653 if(lzw->nextCode - 1 == maxOutSize)
654 {
655 outCodeBits = lzw->codeBits;
656 maxOutSize *= 2;
657 }
658
659 /* clear table if necessary */
660 if(clear)
661 {
662 lzw->codeBits = lzw->codeSize + 1;
663 lzw->clearCode = 1 << lzw->codeSize;
664 lzw->endCode = lzw->clearCode + 1;
665 lzw->maxCodeSize = 2*lzw->clearCode;
666 lzw->maxCode = lzw->clearCode + 2;
667 lzw->nextCode = lzw->maxCode - 1;
668 maxOutSize = 2*lzw->clearCode;
669 outCodeBits = lzw->codeBits;
670 clear = False;
671 }
672 }while (!eod);
673
674 /* flush any chars left */
675 flushBuf;
676
677 /* and close output file */
678 fflush(lzw->f);
679 fclose(lzw->f);
680 lzw->f = NULL;
681 }
682
683 /*******
684 *** Public Functions
685 *******/
686
687 /*****
688 * Name: LZWStreamConvert
689 * Return Type: void
690 * Description: LZW decoder driver
691 * In:
692 * lzw: current LZWStream
693 * Returns:
694 * nothing
695 *****/
696 void
LZWStreamConvert(LZWStream * lzw)697 LZWStreamConvert(LZWStream *lzw)
698 {
699 if(lzw->codeSize >= 8)
700 LZWStreamConvert8OrAbove(lzw);
701 else
702 LZWStreamConvertBelow8(lzw);
703 }
704
705 /*****
706 * Name: LZWStreamInit
707 * Return Type: int
708 * Description: initializes the given stream
709 * In:
710 * lzw: current LZWStream
711 * Returns:
712 * 0 when codeSize is wrong, -1 when no temporary file could be created,
713 * 1 otherwise.
714 *****/
715 int
LZWStreamInit(LZWStream * lzw)716 LZWStreamInit(LZWStream *lzw)
717 {
718 Byte c;
719 int i;
720
721 #ifdef DEBUG
722 char *chPtr = getenv("LZW_DEBUG");
723
724 if(chPtr == '1')
725 lzw_debug = 1;
726 else if(chPtr == '2')
727 lzw_debug = 2;
728 #endif
729 /* no error */
730 lzw->err_msg = NULL;
731
732 /* check if we have the read functions */
733 if(lzw->readOK == NULL || lzw->getData == NULL)
734 {
735 sprintf(msg_buf, "%sno read functions attached!", err_str);
736 lzw->err_msg = msg_buf;
737 return(-2);
738 }
739
740 /* init input side */
741 lzw->done = 0;
742 lzw->curBit = 0;
743 lzw->lastBit = 0;
744 lzw->lastByte = 2;
745
746 for(i = 0; i < 280; i++)
747 lzw->buf[i] = 0;
748 for(i = 0; i < 16; i++)
749 lzw->outBuf[i] = 0;
750
751 /* initialize buffered output */
752 memset(lzw->accum, '\0', BUFFERSIZE);
753 lzw->acount = 0;
754
755 /* close any open files */
756 if(lzw->zPipe)
757 {
758 fclose(lzw->zPipe);
759 lzw->zPipe = NULL;
760 }
761 if(lzw->f)
762 {
763 fclose(lzw->f);
764 lzw->f = NULL;
765 unlink(lzw->zName);
766 }
767
768 /* no data to uncompress yet */
769 lzw->error = False;
770 lzw->uncompressed = False;
771
772 /* temporary output file */
773 tmpnam(lzw->zName);
774 strcat(lzw->zName, ".Z");
775
776 /* open it */
777 if(!(lzw->f = fopen(lzw->zName, "w")))
778 {
779 sprintf(msg_buf, "%scouldn't open temporary file '%s'.",
780 err_str, lzw->zName);
781 lzw->err_msg = msg_buf;
782 return(-1);
783 }
784
785 /*
786 * get codeSize (= how many bits each pixel takes) from ImageBuffer.
787 */
788 if((lzw->readOK(lzw->ib, &c, 1)) == 0)
789 {
790 sprintf(msg_buf, "%scouldn't read GIF codesize.", err_str);
791 lzw->err_msg = msg_buf;
792 return(0);
793 }
794
795 /* GIF lzw codes */
796 lzw->codeSize = (int)((Byte)c); /* initial bits per pixel */
797
798 /* initialize input side */
799 lzw->codeBits = lzw->codeSize + 1;
800 lzw->clearCode = 1 << lzw->codeSize;
801 lzw->endCode = lzw->clearCode + 1;
802 lzw->maxCodeSize = 2*lzw->clearCode;
803 lzw->maxCode = lzw->clearCode + 2;
804 lzw->nextCode = lzw->maxCode;
805
806 /* initialize codeSize < 8 output side */
807 lzw->offset = 0;
808 lzw->clearFlag = False;
809 lzw->n_bits = INIT_BITS;
810 lzw->maxcode8 = MAXCODE(lzw->n_bits);
811 lzw->freeEntry = FIRST;
812
813 /* check clearCode value */
814 if(lzw->clearCode >= MAX_LZW_CODE)
815 {
816 sprintf(msg_buf, "%scorrupt raster data: bad GIF codesize (%i).",
817 err_str, lzw->codeSize);
818 lzw->err_msg = msg_buf;
819 return(0);
820 }
821
822 /* Write compress header */
823 charOut(0x1f);
824 charOut(0x9d);
825
826 /* gif max code length + 1, block mode flag */
827 charOut((MAX_BITS & 0x1f) | 0x80);
828
829 return(1);
830 }
831
832 /*****
833 * Name: LZWStreamCreate
834 * Return Type: LZWStream
835 * Description: allocates a new stream
836 * In:
837 * ib: data input buffer
838 * Returns:
839 * a newly created stream object.
840 *****/
841 LZWStream*
LZWStreamCreate(ImageBuffer * ib,char * zCmd)842 LZWStreamCreate(ImageBuffer *ib, char *zCmd)
843 {
844 static LZWStream *lzw;
845
846 /* create a new stream */
847 if((lzw = (LZWStream*)calloc(1, sizeof(LZWStream))) == NULL)
848 return(NULL);
849
850 /* store ptr to input buffer */
851 lzw->ib = ib;
852
853 /* create uncompress command */
854 strcpy(lzw->zCmd, zCmd != NULL ? zCmd : "uncompress");
855 strcat(lzw->zCmd, " ");
856
857 /* offset for temporary file in which compressed data is to be stored */
858 lzw->zName = lzw->zCmd + strlen(lzw->zCmd);
859
860 /* no default readOK and getData, they need to be set by caller */
861
862 /* and return the new stream */
863 return(lzw);
864 }
865
866 /*****
867 * Name: LZWStreamDestroy
868 * Return Type: void
869 * Description: destroys the given LZW stream
870 * In:
871 * lzw: LZWStream to destroy
872 * Returns:
873 * nothing.
874 *****/
875 void
LZWStreamDestroy(LZWStream * lzw)876 LZWStreamDestroy(LZWStream *lzw)
877 {
878 if(lzw == NULL)
879 return;
880
881 if(lzw->zPipe)
882 fclose(lzw->zPipe);
883 if(lzw->f)
884 fclose(lzw->f);
885 unlink(lzw->zName);
886 free(lzw);
887 }
888
889 /*****
890 * Name: LZWStreamFillBuffer
891 * Return Type: int
892 * Description: read uncompressed data from the stream
893 * In:
894 * lzw: current LZWStream object
895 * data: output buffer
896 * size: size of output buffer
897 * Returns:
898 * no of chars read from stream
899 *****/
900 int
LZWStreamFillBuffer(LZWStream * lzw,unsigned char * data,int size)901 LZWStreamFillBuffer(LZWStream *lzw, unsigned char *data, int size)
902 {
903 int n;
904
905 if(lzw->error)
906 return(0);
907
908 /* uncompress data if not yet done */
909 if(!lzw->uncompressed || lzw->zPipe == NULL)
910 {
911 if(!(LZWStreamUncompressData(lzw)))
912 return(0);
913 }
914 n = fread(data, 1, size, lzw->zPipe);
915 return(n);
916 }
917
918 /*****
919 * Name: LZWStreamUncompress
920 * Return Type: unsigned char *
921 * Description: return an allocated buffer with uncompressed stream data
922 * In:
923 * lzw: current LZWStream
924 * size: size of data read, filled upon return.
925 * Returns:
926 * An allocated buffer when succesfully uncompressed and size is updated to
927 * contain the no of characters read. Upon error, NULL is returned and size
928 * is set to 0.
929 *****/
930 unsigned char *
LZWStreamUncompress(LZWStream * lzw,int * size)931 LZWStreamUncompress(LZWStream *lzw, int *size)
932 {
933 static unsigned char *data;
934
935 *size = 0;
936
937 if(lzw->error)
938 return(NULL);
939
940 /* no error */
941 lzw->err_msg = NULL;
942
943 /* uncompress data if not yet done */
944 if(!lzw->uncompressed || lzw->zPipe == NULL)
945 {
946 if(!(LZWStreamUncompressData(lzw)))
947 return(NULL);
948 }
949
950 fseek(lzw->zPipe, 0L, SEEK_END);
951 *size = ftell(lzw->zPipe);
952
953 /* sanity check */
954 if(*size == 0)
955 {
956 sprintf(msg_buf, "%szero-length data file.", err_str);
957 lzw->err_msg = msg_buf;
958 return(NULL);
959 }
960
961 rewind(lzw->zPipe);
962
963 data = (unsigned char*)malloc(*size*sizeof(unsigned char));
964
965 /* read it all */
966 (void)fread(data, *size, 1, lzw->zPipe);
967
968 /* close and remove file */
969 if(lzw->zPipe)
970 {
971 fclose(lzw->zPipe);
972 lzw->zPipe = NULL;
973 }
974 if(lzw->f)
975 {
976 fclose(lzw->f);
977 lzw->f = NULL;
978 unlink(lzw->zName);
979 }
980 /* and return it */
981 return(data);
982 }
983
984 int
LZWStreamGetCodeSize(LZWStream * lzw)985 LZWStreamGetCodeSize(LZWStream *lzw)
986 {
987 return(lzw->codeSize);
988 }
989