fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGGIFImageFileType.cpp
blob737809c5dcde0b870ad1378b9a165324e5043f93
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 //-------------------------------
39 // Includes
40 //-------------------------------
42 #include <cstdlib>
43 #include <cstdio>
44 #include <setjmp.h>
45 #include <cstring>
46 #include <cctype>
48 #include "OSGConfig.h"
50 #ifdef OSG_SGI_LIB
51 #include <limits>
52 #endif
53 #include "OSGGIFImageFileType.h"
54 #include "OSGLog.h"
56 #ifndef OSG_DO_DOC
57 # ifdef OSG_WITH_GIF
58 # define OSG_GIF_ARG(ARG) ARG
59 # else
60 # define OSG_GIF_ARG(ARG)
61 # endif
62 #else
63 # define OSG_GIF_ARG(ARG) ARG
64 #endif
66 #ifdef OSG_WITH_GIF
69 /*! \class OSG::GIFImageFileType
71 Image File Type to read/write and store/restore Image objects as
72 GIF data.
74 All the type specific code is included in the class. Does
75 not depend on external libs.
77 You have to --enable-gif in the configure line to enable
78 the singleton object.
83 //--- GIF-INCLUDE START ----------------------------------------------------
85 #define GIF_MAXCOLORS 256
87 typedef enum
89 gif_image,
90 gif_comment,
91 gif_text
92 } GIFStreamType;
94 typedef enum
96 gif_no_disposal = 0,
97 gif_keep_disposal = 1,
98 gif_color_restore = 2,
99 gif_image_restore = 3
101 GIFDisposalType;
103 typedef struct
105 int transparent; /* transparency index */
106 int delayTime; /* Time in 1/100 of a second */
107 int inputFlag; /* wait for input after display */
108 GIFDisposalType disposal;
109 } GIF89info;
111 typedef struct GIFData
113 GIF89info info;
114 int x, y;
115 int width, height;
116 GIFStreamType type;
117 union
119 struct
121 int cmapSize;
122 unsigned char cmapData[GIF_MAXCOLORS][3];
123 unsigned char *data;
124 int interlaced;
125 } image;
126 struct
128 int fg, bg;
129 int cellWidth, cellHeight;
130 int len;
131 char *text;
132 } text;
133 struct
135 int len;
136 char *text;
137 } comment;
138 } data;
140 struct GIFData *next;
141 } GIFData;
143 typedef struct
145 int width, height;
147 int colorResolution;
148 int colorMapSize;
149 int cmapSize;
150 unsigned char cmapData[GIF_MAXCOLORS][3];
152 int background;
153 int aspectRatio;
155 GIFData *data;
156 } GIFStream;
159 static GIFStream *GIFRead (std::istream &is);
160 int GIFTest (char *);
161 int GIFWrite (char *, GIFStream *, int);
162 static int GIFWriteFP(FILE *, GIFStream *, int);
163 static int GIFFree (const GIFStream *);
165 #endif // OSG_WITH_GIF
167 //--- GIF INCLUDE END ----------------------------------------------------
169 static const OSG::Char8 *gifSuffixArray[] =
171 "gif"
174 OSG_USING_NAMESPACE
176 GIFImageFileType GIFImageFileType::_the("image/gif",
177 gifSuffixArray,
178 sizeof(gifSuffixArray));
182 //-------------------------------------------------------------------------
183 /*! Tries to fill the image object with the data read from
184 the given fileName. Returns true on success.
187 bool GIFImageFileType::read( Image *OSG_GIF_ARG(pImage),
188 std::istream &OSG_GIF_ARG(is),
189 const std::string &OSG_GIF_ARG(mimetype))
191 bool retCode = false;
193 #ifdef OSG_WITH_GIF
194 Image::PixelFormat pixelFormat = Image::OSG_INVALID_PF;
195 const GIFStream *gifStream = GIFRead(is);
196 const GIFData *gifData = 0;
197 bool isColor;
198 int i, j, destI, lineSize, lineEnd;
199 unsigned red, green, blue;
200 int transparentIndex;
201 int streamWidth = 0, streamHeight = 0;
202 int curWidth = 0, curHeight = 0, channel = 0;
203 int xOff = 0, yOff = 0;
204 const unsigned char *srcData = 0;
205 unsigned char *destData = 0;
206 int colorIndex;
207 unsigned frameCount = 0, currentFrame = 0;
208 const unsigned char *colorMap = 0;
210 // int imageSize = 0;
211 int colorMapSize;
212 Time frameDelay;
214 if(gifStream)
216 frameCount = 0;
218 for(gifData = gifStream->data; gifData; gifData = gifData->next)
220 if(gifData->type == gif_image)
221 frameCount++;
225 FDEBUG(("GIF Frames: %d\n", frameCount));
227 if(gifStream)
229 streamWidth = gifStream->width;
230 streamHeight = gifStream->height;
232 for(gifData = gifStream->data; gifData; gifData = gifData->next)
234 switch(gifData->type)
236 case gif_image:
237 if(frameCount)
239 FDEBUG(("Try to copy GIF Anim Frame %d/%d\n",
240 (currentFrame + 1), frameCount));
243 // get the att.
244 transparentIndex = gifData->info.transparent;
245 frameDelay = float(gifData->info.delayTime) / 100.0f;
246 curWidth = gifData->width;
247 curHeight = gifData->height;
248 xOff = gifData->x;
249 yOff = gifData->y;
251 // check if the movie is color or greyscale
252 isColor = false;
253 if(gifData->data.image.cmapSize > 0)
255 colorMapSize = gifData->data.image.cmapSize;
256 colorMap =
257 reinterpret_cast<const unsigned char *>(
258 gifData->data.image.cmapData);
260 // cout << "INFO: Use gifData colorMap" << endl;
262 else if(gifStream->cmapSize > 0)
264 colorMapSize = gifStream->cmapSize;
265 colorMap =
266 reinterpret_cast<const unsigned char *>(
267 gifStream->cmapData);
269 // cout << "INFO: Use gifStream colorMap" << endl;
271 else
273 FWARNING(("Bad color map in "
274 "GIFImageFileType::read()\n"));
275 colorMapSize = 0;
278 for(i = 0; i < colorMapSize; i++)
280 if(i != transparentIndex)
282 red = colorMap[i * 3 + 0];
283 green = colorMap[i * 3 + 1];
284 blue = colorMap[i * 3 + 2];
286 if(red != green || red != blue)
288 isColor = true;
289 break;
294 // calculate the movie channel
295 channel =
296 (isColor ? 3 : 1) + (transparentIndex >= 0 ? 1 : 0);
298 if(currentFrame)
300 // is not the first frame
301 if((channel == pImage->getBpp()) &&
302 (streamWidth == pImage->getWidth()) &&
303 (streamHeight == pImage->getHeight()))
305 destData = pImage->editData(0, currentFrame);
307 else
309 destData = pImage->editData(0, currentFrame);
311 // This is probably wrong, but it's a start
312 switch(gifData->info.disposal)
314 case gif_no_disposal:
315 break;
317 case gif_keep_disposal:
318 memcpy(destData,
319 pImage->getData(0,
320 currentFrame - 1),
321 pImage->getWidth () *
322 pImage->getHeight() *
323 channel);
324 break;
326 case gif_color_restore:
328 unsigned char r,g,b,a;
329 Int32 bgindex = gifStream->background;
330 unsigned char *d = destData;
332 r = colorMap[bgindex * 3 + 0];
333 g = colorMap[bgindex * 3 + 1];
334 b = colorMap[bgindex * 3 + 2];
335 a = (bgindex == transparentIndex) ?
336 0 : 255;
338 for(UInt32 pixel =
339 pImage->getWidth () *
340 pImage->getHeight();
341 pixel > 0; --pixel, d += channel)
343 d[0] = r;
344 d[1] = g;
345 d[2] = b;
346 if(channel == 4)
347 d[3] = a;
350 break;
352 case gif_image_restore:
353 memcpy(destData,
354 pImage->getData(
356 (currentFrame >= 2) ?
357 (currentFrame - 2) : 0),
358 pImage->getWidth () *
359 pImage->getHeight() *
360 channel);
361 break;
362 default:
363 FWARNING(("Unknown GIF disposal "
364 "mode %d\n",
365 gifData->info.disposal));
366 break;
370 else
372 switch(channel)
374 case 1:
375 pixelFormat = Image::OSG_L_PF;
376 break;
377 case 2:
378 pixelFormat = Image::OSG_LA_PF;
379 break;
380 case 3:
381 pixelFormat = Image::OSG_RGB_PF;
382 break;
383 case 4:
384 pixelFormat = Image::OSG_RGBA_PF;
385 break;
387 pImage->set(pixelFormat,
388 streamWidth,
389 streamHeight,
390 1, 1,
391 frameCount, frameDelay);
393 destData = pImage->editData();
396 // copy the image data
397 lineSize = pImage->getWidth() * channel;
398 lineEnd = curWidth * channel + xOff * channel;
399 srcData = gifData->data.image.data;
400 destData =
401 destData + ((pImage->getHeight() - yOff - 1)*lineSize);
403 switch(channel)
405 case 1: // Greyscale without Alpha
406 destI = 0;
407 for(i = curWidth * curHeight; i--;)
409 destData[destI++] = colorMap[*srcData++ *3];
410 if(destI >= lineEnd)
412 destI = 0;
413 destData -= lineSize;
416 break;
418 case 2: // Greyscale with Alpha
419 destI = 0;
420 for(i = curWidth * curHeight; i--;)
422 colorIndex = *srcData++;
423 if(colorIndex == transparentIndex)
425 destData[destI++] = 0;
426 destData[destI++] = 0;
428 else
430 destData[destI++] = colorMap[colorIndex*3];
431 destData[destI++] = 255;
434 if(destI >= lineEnd)
436 destI = 0;
437 destData -= lineSize;
440 break;
442 case 3: // RGB without Alpha
443 destI = 0;
444 for(i = curWidth * curHeight; i--;)
446 colorIndex = *srcData++;
447 for(j = 0; j < 3; j++)
449 destData[destI++] =
450 colorMap[colorIndex * 3 + j];
453 if(destI >= lineEnd)
455 destI = 0;
456 destData -= lineSize;
459 break;
461 case 4: // RGB with Alpha
462 destI = xOff * 4;
464 for(i = curWidth * curHeight; i--;)
466 colorIndex = *srcData++;
467 if(colorIndex == transparentIndex)
469 #if 0
470 for(j = 0; j < 3; j++)
471 destData[destI++] = 0; // RGB
472 destData[destI++] = 0; // ALPHA
473 #endif
475 destI += 4;
477 else
479 for(j = 0; j < 3; j++)
481 destData[destI++] =
482 colorMap[colorIndex * 3 + j];// RGB
485 destData[destI++] = 255; // ALPHA
488 if(destI >= lineEnd)
490 destI = xOff * 4;
491 destData -= lineSize;
494 break;
497 retCode = true;
499 currentFrame++;
501 break;
502 case gif_comment:
503 break;
504 case gif_text:
505 break;
509 GIFFree(gifStream);
511 else
513 retCode = false;
515 #endif
517 return retCode;
520 //-------------------------------------------------------------------------
521 /*! Tries to write the image object to the given fileName.
522 Returns true on success.
525 bool GIFImageFileType::write(const Image * ,
526 std::ostream &,
527 const std::string &)
529 #ifdef OSG_WITH_GIF
530 SWARNING << getMimeType() << " write is not implemented " << endLog;
532 #else
533 SWARNING << getMimeType()
534 << " write is not compiled into the current binary "
535 << endLog;
536 #endif
538 return false;
541 //-------------------------------------------------------------------------
543 Tries to determine the mime type of the data provided by an input stream
544 by searching for magic bytes. Returns the mime type or an empty string
545 when the function could not determine the mime type.
548 std::string GIFImageFileType::determineMimetypeFromStream(std::istream &is)
550 char filecode[4];
552 is.read(filecode, 4);
553 is.seekg(-4, std::ios::cur);
555 return strncmp(filecode, "GIF8", 4) == 0 ?
556 std::string(getMimeType()) : std::string();
559 bool GIFImageFileType::validateHeader(const Char8 *fileName, bool &implemented)
561 implemented = true;
563 if(fileName == NULL)
564 return false;
566 FILE *file = fopen(fileName, "rb");
568 if(file == NULL)
569 return false;
571 std::string magic;
573 magic.resize(4);
575 fread(static_cast<void *>(&magic[0]), 4, 1, file);
577 fclose(file);
579 if(magic == "GIF8")
581 return true;
584 return false;
587 //-------------------------------------------------------------------------
588 /*! Constructor used for the singleton object
591 GIFImageFileType::GIFImageFileType(const Char8 *mimeType,
592 const Char8 *suffixArray[],
593 UInt16 suffixByteCount) :
594 Inherited(mimeType,suffixArray, suffixByteCount)
598 //-------------------------------------------------------------------------
599 /*! Destructor
602 GIFImageFileType::~GIFImageFileType(void)
606 #ifdef OSG_WITH_GIF
608 //--- GIF-READ START ----------------------------------------------------
610 ** Copyright 1994, Home Pages, Inc.
612 ** Please read the file COPYRIGHT for specific information.
614 ** Home Pages, Inc.
615 ** 257 Castro St. Suite 219
616 ** Mountain View, CA 94041
618 ** Phone: 1 415 903 5353
619 ** Fax: 1 415 903 5345
621 ** EMail: support@homepages.com
624 /* +-------------------------------------------------------------------+ */
625 /* | Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) | */
626 /* | Permission to use, copy, modify, and distribute this software | */
627 /* | and its documentation for any purpose and without fee is hereby | */
628 /* | granted, provided that the above copyright notice appear in all | */
629 /* | copies and that both that copyright notice and this permission | */
630 /* | notice appear in supporting documentation. This software is | */
631 /* | provided "as is" without express or implied warranty. | */
632 /* +-------------------------------------------------------------------+ */
633 #define GIF_TRUE 1
634 #define GIF_FALSE 0
636 #define MAX_LWZ_BITS 12
638 #define INTERLACE 0x40
639 #define LOCALCOLORMAP 0x80
641 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
642 #define ReadOK(is, buffer, len) (is.read(reinterpret_cast<char*>(buffer), \
643 len).gcount() == len)
644 #define MKINT(a, b) (((b) << 8) | (a))
645 #define NEW(x) (static_cast<x *>(malloc(sizeof(x))))
646 /***************************************************************************
648 * ERROR() -- should not return
649 * INFO_MSG() -- info message, can be ignored
651 ***************************************************************************/
653 #if 0
654 #define INFO_MSG(fmt) pm_message fmt
655 #define ERROR(str) pm_error(str)
656 #else
657 #if 0
658 #define INFO_MSG(fmt)
659 #define ERROR(str) do { RWSetMsg(str); longjmp(setjmp_buffer, 1); } while(0)
660 #else
661 #define INFO_MSG(fmt) { FINFO(("Info loading gif: '%s'!\n", fmt)); }
662 #define GIF_ERROR(str) { FWARNING(("Error loading gif: '%s'!\n", str)); \
663 longjmp(setjmp_buffer, 1); }
664 #endif
665 #endif
667 /***************************************************************************/
669 static int readColorMap(std::istream &, int, unsigned char [GIF_MAXCOLORS][3]);
670 static int GetDataBlock(std::istream &, unsigned char *);
671 static void readImage (std::istream &, int, int, int, unsigned char *);
673 static jmp_buf setjmp_buffer;
675 static int verbose = GIF_FALSE;
676 //static int showComment = GIF_FALSE;
678 /* */
679 static GIFStream *GIFRead(std::istream &is)
681 unsigned char buf[256];
682 unsigned char c;
683 GIFStream *gifStream = 0;
684 GIFData *cur, **end;
685 GIF89info info = {0, 0, 0, gif_no_disposal};
686 int resetInfo = GIF_TRUE;
687 int n;
689 if(setjmp(setjmp_buffer))
690 goto out;
692 if(!ReadOK(is, buf, 6))
694 GIF_ERROR("error reading magic number");
697 if(strncmp(reinterpret_cast<char *>(buf), "GIF", 3) != 0)
698 GIF_ERROR("not a GIF file");
700 if((strncmp((reinterpret_cast<char *>(buf)) + 3, "87a", 3) != 0) &&
701 (strncmp((reinterpret_cast<char *>(buf)) + 3, "89a", 3) != 0))
703 GIF_ERROR("bad version number, not '87a' or '89a'");
706 if(!ReadOK(is, buf, 7))
708 GIF_ERROR("failed to read screen descriptor");
711 gifStream = NEW(GIFStream);
713 gifStream->width = MKINT(buf[0], buf[1]);
714 gifStream->height = MKINT(buf[2], buf[3]);
716 gifStream->cmapSize = 2 << (buf[4] & 0x07);
717 gifStream->colorMapSize = gifStream->cmapSize;
718 gifStream->colorResolution = (int(buf[4] & 0x70) >> 3) + 1;
719 gifStream->background = buf[5];
720 gifStream->aspectRatio = buf[6];
722 gifStream->data = NULL;
724 end = &gifStream->data;
727 ** Global colormap is present.
729 if(BitSet(buf[4], LOCALCOLORMAP))
731 if(readColorMap(is, gifStream->cmapSize, gifStream->cmapData))
733 GIF_ERROR("unable to get global colormap");
736 else
738 gifStream->cmapSize = 0;
739 gifStream->background = -1;
742 if(gifStream->aspectRatio != 0 && gifStream->aspectRatio != 49)
744 INFO_MSG(("warning - non-square pixels"));
747 while(ReadOK(is, &c, 1) && c != ';')
749 if(resetInfo)
751 info.disposal = static_cast<GIFDisposalType>(0);
752 info.inputFlag = 0;
753 info.delayTime = 0;
754 info.transparent = -1;
755 resetInfo = GIF_FALSE;
758 cur = NULL;
760 if(c == '!')
761 { /* Extension */
762 if(!ReadOK(is, &c, 1))
764 GIF_ERROR("EOF / read error on extention function code");
767 if(c == 0xf9)
768 { /* graphic control */
769 (void) GetDataBlock(is, buf);
770 info.disposal =
771 static_cast<GIFDisposalType>((buf[0] >> 2) & 0x7);
772 info.inputFlag = (buf[0] >> 1) & 0x1;
773 info.delayTime = MKINT(buf[1], buf[2]);
774 if(BitSet(buf[0], 0x1))
775 info.transparent = buf[3];
777 while(GetDataBlock(is, buf) != 0)
780 else if(c == 0xfe || c == 0x01)
782 int len = 0;
783 int size = 256;
784 char *text = NULL;
787 ** Comment or Plain Text
789 cur = NEW(GIFData);
791 if(c == 0x01)
793 (void) GetDataBlock(is, buf);
795 cur->type = gif_text;
796 cur->info = info;
797 cur->x = MKINT(buf[0], buf[1]);
798 cur->y = MKINT(buf[2], buf[3]);
799 cur->width = MKINT(buf[4], buf[5]);
800 cur->height = MKINT(buf[6], buf[7]);
802 cur->data.text.cellWidth = buf[8];
803 cur->data.text.cellHeight = buf[9];
804 cur->data.text.fg = buf[10];
805 cur->data.text.bg = buf[11];
807 resetInfo = GIF_TRUE;
809 else
811 cur->type = gif_comment;
814 text = static_cast<char *>(malloc(size));
816 while((n = GetDataBlock(is, buf)) != 0)
818 if(n + len >= size)
820 text = static_cast<char *>(realloc(text, size += 256));
823 memcpy(text + len, buf, n);
824 len += n;
827 if(c == 0x01)
829 cur->data.text.len = len;
830 cur->data.text.text = text;
832 else
834 cur->data.comment.len = len;
835 cur->data.comment.text = text;
838 else
841 ** Unrecogonized extension, consume it.
843 while(GetDataBlock(is, buf) > 0)
847 else if(c == ',')
849 if(!ReadOK(is, buf, 9))
851 GIF_ERROR("couldn't read left/top/width/height");
854 cur = NEW(GIFData);
856 cur->type = gif_image;
857 cur->info = info;
858 cur->x = MKINT(buf[0], buf[1]);
859 cur->y = MKINT(buf[2], buf[3]);
860 cur->width = MKINT(buf[4], buf[5]);
861 cur->height = MKINT(buf[6], buf[7]);
862 cur->data.image.cmapSize = 1 << ((buf[8] & 0x07) + 1);
863 if(BitSet(buf[8], LOCALCOLORMAP))
865 if(readColorMap(is, cur->data.image.cmapSize,
866 cur->data.image.cmapData))
868 GIF_ERROR("unable to get local colormap");
871 else
873 cur->data.image.cmapSize = 0;
876 cur->data.image.data = static_cast<unsigned char *>(
877 malloc(cur->width * cur->height));
878 cur->data.image.interlaced = BitSet(buf[8], INTERLACE);
879 readImage(is, BitSet(buf[8], INTERLACE), cur->width, cur->height,
880 cur->data.image.data);
882 resetInfo = GIF_TRUE;
884 else
886 FINFO(("Info loading gif: bogus character 0x%02x, ignoring",
887 int(c)));
890 if(cur != NULL)
892 *end = cur;
893 end = &cur->next;
894 cur->next = NULL;
898 if(c != ';')
899 GIF_ERROR("EOF / data stream");
901 out:
902 return gifStream;
905 /* */
906 static int GIFFreeData(const GIFData *gifData)
908 int retCode = 0;
910 if(gifData)
912 switch(gifData->type)
914 case gif_image:
915 if(gifData->data.image.data)
917 free(gifData->data.image.data);
919 break;
920 case gif_comment:
921 if(gifData->data.comment.text)
923 free(gifData->data.comment.text);
925 break;
926 case gif_text:
927 if(gifData->data.text.text)
929 free(gifData->data.text.text);
931 break;
934 retCode = 1;
936 else
937 retCode = 0;
939 return retCode;
942 /* */
943 static int GIFFree(const GIFStream *gifStream)
945 int retCode = 1;
946 GIFData *gifData, *gifNext;
948 if(gifStream)
950 gifData = gifStream->data;
951 while(gifData)
953 gifNext = gifData->next;
954 GIFFreeData(gifData);
955 free(gifData);
956 gifData = gifNext;
960 return retCode;
963 /* */
964 static int readColorMap(std::istream &is, int size, unsigned char data[GIF_MAXCOLORS][3])
966 int i;
967 unsigned char rgb[3 * GIF_MAXCOLORS];
968 unsigned char *cp = rgb;
970 if(!ReadOK(is, rgb, size * 3))
971 return GIF_TRUE;
973 for(i = 0; i < size; i++)
975 data[i][0] = *cp++;
976 data[i][1] = *cp++;
977 data[i][2] = *cp++;
980 return GIF_FALSE;
986 static int ZeroDataBlock = GIF_FALSE;
988 /* */
990 static int GetDataBlock(std::istream &is, unsigned char *buf)
992 unsigned char count;
994 if(!ReadOK(is, &count, 1))
996 INFO_MSG(("error in getting DataBlock size"));
997 return -1;
1000 ZeroDataBlock = count == 0;
1002 if((count != 0) && (!ReadOK(is, buf, count)))
1004 INFO_MSG(("error in reading DataBlock"));
1005 return -1;
1008 return count;
1016 ** Pulled out of nextCode
1018 static int curbit, lastbit, get_done, last_byte;
1019 static int return_clear;
1022 ** Out of nextLWZ
1024 static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
1025 static int code_size, set_code_size;
1026 static int max_code, max_code_size;
1027 static int clear_code, end_code;
1029 /* */
1031 static void initLWZ(int input_code_size)
1033 // static int inited = GIF_FALSE;
1035 set_code_size = input_code_size;
1036 code_size = set_code_size + 1;
1037 clear_code = 1 << set_code_size ;
1038 end_code = clear_code + 1;
1039 max_code_size = 2 * clear_code;
1040 max_code = clear_code + 2;
1042 curbit = lastbit = 0;
1043 last_byte = 2;
1044 get_done = GIF_FALSE;
1046 return_clear = GIF_TRUE;
1048 sp = stack;
1051 /* */
1052 static int nextCode(std::istream &is, int code_size_in)
1054 static unsigned char buf[280];
1055 static int maskTbl[16] =
1057 0x0000,
1058 0x0001,
1059 0x0003,
1060 0x0007,
1061 0x000f,
1062 0x001f,
1063 0x003f,
1064 0x007f,
1065 0x00ff,
1066 0x01ff,
1067 0x03ff,
1068 0x07ff,
1069 0x0fff,
1070 0x1fff,
1071 0x3fff,
1072 0x7fff,
1074 int i, j, ret, end;
1076 if(return_clear)
1078 return_clear = GIF_FALSE;
1079 return clear_code;
1082 end = curbit + code_size_in;
1084 if(end >= lastbit)
1086 int count;
1088 if(get_done)
1090 if(curbit >= lastbit)
1092 GIF_ERROR("ran off the end of my bits");
1095 return -1;
1098 buf[0] = buf[last_byte - 2];
1099 buf[1] = buf[last_byte - 1];
1101 if((count = GetDataBlock(is, &buf[2])) == 0)
1102 get_done = GIF_TRUE;
1104 last_byte = 2 + count;
1105 curbit = (curbit - lastbit) + 16;
1106 lastbit = (2 + count) * 8;
1108 end = curbit + code_size_in;
1111 j = end / 8;
1112 i = curbit / 8;
1114 if(i == j)
1115 ret = buf[i];
1116 else if(i + 1 == j)
1117 ret = buf[i] | (buf[i + 1] << 8);
1118 else
1120 ret = buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16);
1123 ret = (ret >> (curbit % 8)) & maskTbl[code_size_in];
1125 curbit += code_size_in;
1127 return ret;
1130 #define readLWZ(fd) ((sp > stack) ? *--sp : nextLWZ(fd))
1132 /* */
1133 static int nextLWZ(std::istream &is)
1135 static int table[2][(1 << MAX_LWZ_BITS)];
1136 static int firstcode, oldcode;
1137 int code, incode;
1138 register int i;
1140 while((code = nextCode(is, code_size)) >= 0)
1142 if(code == clear_code)
1144 for(i = 0; i < clear_code; ++i)
1146 table[0][i] = 0;
1147 table[1][i] = i;
1150 for(; i < (1 << MAX_LWZ_BITS); ++i)
1151 table[0][i] = table[1][i] = 0;
1152 code_size = set_code_size + 1;
1153 max_code_size = 2 * clear_code;
1154 max_code = clear_code + 2;
1155 sp = stack;
1158 firstcode = oldcode = nextCode(is, code_size);
1159 } while(firstcode == clear_code);
1161 return firstcode;
1164 if(code == end_code)
1166 int count;
1167 unsigned char buf[260];
1169 if(ZeroDataBlock)
1170 return -2;
1172 while((count = GetDataBlock(is, buf)) > 0)
1175 if(count != 0)
1177 INFO_MSG(("missing EOD in data stream"));
1180 return -2;
1183 incode = code;
1185 if(code >= max_code)
1187 *sp++ = firstcode;
1188 code = oldcode;
1191 while(code >= clear_code)
1193 *sp++ = table[1][code];
1194 if(code == table[0][code])
1196 GIF_ERROR("circular table entry BIG ERROR");
1199 code = table[0][code];
1202 *sp++ = firstcode = table[1][code];
1204 if((code = max_code) < (1 << MAX_LWZ_BITS))
1206 table[0][code] = oldcode;
1207 table[1][code] = firstcode;
1208 ++max_code;
1209 if((max_code >= max_code_size) &&
1210 (max_code_size < (1 << MAX_LWZ_BITS)))
1212 max_code_size *= 2;
1213 ++code_size;
1217 oldcode = incode;
1219 if(sp > stack)
1220 return *--sp;
1223 return code;
1226 /* */
1227 static void readImage(std::istream &is, int interlace, int width, int height,
1228 unsigned char *data)
1230 unsigned char *dp, c;
1232 int v, xpos = 0, ypos = 0;
1234 // int pass = 0;
1236 ** Initialize the Compression routines
1238 if(!ReadOK(is, &c, 1))
1240 GIF_ERROR("EOF / read error on image data");
1243 initLWZ(c);
1245 if(verbose)
1247 FINFO(("Info loading gif: reading %d by %d%s GIF image",
1248 width, height, interlace ? " interlaced" : ""));
1251 if(interlace)
1253 int i;
1254 int pass = 0, step = 8;
1256 for(i = 0; i < height; i++)
1258 dp = &data[width * ypos];
1259 for(xpos = 0; xpos < width; xpos++)
1261 if((v = readLWZ(is)) < 0)
1262 goto fini;
1264 *dp++ = v;
1267 if((ypos += step) >= height)
1271 if(pass++ > 0)
1272 step /= 2;
1273 ypos = step / 2;
1274 } while(ypos > height);
1278 else
1280 dp = data;
1281 for(ypos = 0; ypos < height; ypos++)
1283 for(xpos = 0; xpos < width; xpos++)
1285 if((v = readLWZ(is)) < 0)
1286 goto fini;
1288 *dp++ = v;
1293 fini:
1294 if(readLWZ(is) >= 0)
1296 INFO_MSG(("too much input data, ignoring extra..."));
1299 return;
1302 //--- GIF-READ END ------------------------------------------------------
1303 //--- GIF-WRITE START ---------------------------------------------------
1305 ** Copyright 1994, Home Pages, Inc.
1307 ** Please read the file COPYRIGHT for specific information.
1309 ** Home Pages, Inc.
1310 ** 257 Castro St. Suite 219
1311 ** Mountain View, CA 94041
1313 ** Phone: 1 415 903 5353
1314 ** Fax: 1 415 903 5345
1316 ** EMail: support@homepages.com
1319 /* +-------------------------------------------------------------------+ */
1320 /* | Copyright 1993, David Koblas (koblas@netcom.com) | */
1321 /* | | */
1322 /* | Permission to use, copy, modify, and to distribute this software | */
1323 /* | and its documentation for any purpose is hereby granted without | */
1324 /* | fee, provided that the above copyright notice appear in all | */
1325 /* | copies and that both that copyright notice and this permission | */
1326 /* | notice appear in supporting documentation. There is no | */
1327 /* | representations about the suitability of this software for | */
1328 /* | any purpose. this software is provided "as is" without express | */
1329 /* | or implied warranty. | */
1330 /* | | */
1331 /* +-------------------------------------------------------------------+ */
1332 /* ppmtogif.c - read a portable pixmap and produce a GIF file
1334 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
1335 ** Lempel-Zim compression based on "compress".
1337 ** Copyright (C) 1989 by Jef Poskanzer.
1339 ** Permission to use, copy, modify, and distribute this software and its
1340 ** documentation for any purpose and without fee is hereby granted, provided
1341 ** that the above copyright notice appear in all copies and that both that
1342 ** copyright notice and this permission notice appear in supporting
1343 ** documentation. This software is provided "as is" without express or
1344 ** implied warranty.
1346 ** The Graphics Interchange Format(c) is the Copyright property of
1347 ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
1348 ** CompuServe Incorporated.
1350 #define GIF_TRUE 1
1351 #define GIF_FALSE 0
1353 #define PUTBYTE(v, fp) putc(v, fp)
1354 #define PUTWORD(v, fp) \
1355 do \
1357 putc(((v) & 0xff), fp); \
1358 putc((((v) >> 8) & 0xff), fp); \
1359 } while(0)
1361 * a code_int must be able to hold 2**BITS values of type int, and also -1
1363 typedef int code_int;
1365 typedef long int count_int;
1367 static void putImage(FILE *, int, int, int, int, unsigned char *);
1368 static void putColorMap(FILE *, int, unsigned char[GIF_MAXCOLORS][3]);
1369 static void putDataBlocks(FILE *fp, int, unsigned char *);
1370 static void putGif89Info(FILE *, GIF89info *);
1372 static void output(code_int code);
1373 static void cl_block(void);
1374 static void cl_hash(count_int hsize);
1375 static void char_init(void);
1376 static void char_out(int c);
1377 static void flush_char(void);
1382 struct cval
1384 int idx, cnt;
1387 /* */
1388 static int cvalCMP(struct cval *a, struct cval *b)
1390 return b->cnt - a->cnt;
1393 /* */
1394 static int optimizeCMAP(GIFStream *stream)
1396 GIFData *cur = 0, *img = 0;
1397 int count = 0;
1399 for(cur = stream->data; cur != NULL; cur = cur->next)
1401 if(cur->type == gif_image)
1403 img = cur;
1404 count++;
1409 ** No images, no optimizations...
1410 ** or too many images...
1412 if(count == 0 || count > 1)
1413 return 0;
1416 ** One image, nice and simple...
1417 ** Insure there is a global colormap, and optimize the
1418 ** image too it.
1421 int size;
1422 unsigned char *dp = img->data.image.data;
1423 unsigned char *ep = dp + img->width * img->height;
1424 struct cval vals[256];
1425 int i;
1427 // int j;
1428 unsigned char tmap[256][3], rmap[256];
1430 if((size = img->data.image.cmapSize) == 0)
1431 size = stream->cmapSize;
1433 for(i = 0; i < size; i++)
1435 vals[i].idx = i;
1436 vals[i].cnt = 0;
1439 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
1440 vals[*dp].cnt++;
1443 ** Quite, I'm doing a bubble sort... ACK!
1445 qsort(vals, size, sizeof(vals[0]),
1446 reinterpret_cast<int(*) (const void *, const void *)>(cvalCMP));
1448 for(i = 0; i < size; i++)
1449 if(vals[i].idx != i)
1450 break;
1453 ** Already sorted, no change!
1455 if(i == size)
1456 return 1;
1457 for(i = 0; i < size; i++)
1458 rmap[vals[i].idx] = i;
1461 ** Now reorder the colormap, and the image
1463 for(dp = img->data.image.data, i = 0; dp < ep; i++, dp++)
1464 *dp = rmap[*dp];
1465 if(img->info.transparent != -1)
1467 img->info.transparent = rmap[img->info.transparent];
1471 ** Toast the local colormap
1473 if(img->data.image.cmapSize != 0)
1475 for(i = 0; i < size; i++)
1477 stream->cmapData[i][0] = img->data.image.cmapData[i][0];
1478 stream->cmapData[i][1] = img->data.image.cmapData[i][1];
1479 stream->cmapData[i][2] = img->data.image.cmapData[i][2];
1482 img->data.image.cmapSize = 0;
1483 stream->cmapSize = size;
1487 ** Now finally reorer the colormap
1489 for(i = 0; i < size; i++)
1491 tmap[i][0] = stream->cmapData[i][0];
1492 tmap[i][1] = stream->cmapData[i][1];
1493 tmap[i][2] = stream->cmapData[i][2];
1496 for(i = 0; i < size; i++)
1498 stream->cmapData[rmap[i]][0] = tmap[i][0];
1499 stream->cmapData[rmap[i]][1] = tmap[i][1];
1500 stream->cmapData[rmap[i]][2] = tmap[i][2];
1504 return 1;
1508 ** Return the ceiling log of n
1510 static int binaryLog(int val)
1512 int i;
1514 if(val == 0)
1515 return 0;
1517 for(i = 1; i <= 8; i++)
1518 if(val <= (1 << i))
1519 return i;
1520 return 8;
1523 #ifdef __sgi
1524 #pragma set woff 1209
1525 #endif
1527 /* */
1528 static int GIFWriteFP(FILE *fp, GIFStream *stream, int optimize)
1530 GIFData *cur;
1531 int flag = GIF_FALSE;
1532 int c;
1533 int globalBitsPP = 0;
1534 int resolution;
1536 if(fp == NULL)
1537 return GIF_TRUE;
1538 if(stream == NULL)
1539 return GIF_FALSE;
1542 ** First find if this is a 87A or an 89A GIF image
1543 ** also, figure out the color resolution of the image.
1545 resolution = binaryLog(stream->cmapSize) - 1;
1546 for(cur = stream->data; !flag && cur != NULL; cur = cur->next)
1548 if(cur->type == gif_text || cur->type == gif_comment)
1550 flag = GIF_TRUE;
1552 else if(cur->type == gif_image)
1554 int v = binaryLog(cur->data.image.cmapSize);
1556 if(v > resolution)
1557 resolution = v;
1560 ** Uses one of the 89 extensions.
1562 if(cur->info.transparent != -1 ||
1563 cur->info.delayTime != 0 ||
1564 cur->info.inputFlag != 0 ||
1565 cur->info.disposal != 0)
1566 flag = GIF_TRUE;
1573 if(optimize)
1574 optimize = optimizeCMAP(stream);
1576 fwrite(flag ? "GIF89a" : "GIF87a", 1, 6, fp);
1578 PUTWORD(stream->width, fp);
1579 PUTWORD(stream->height, fp);
1582 ** assume 256 entry color resution, and non sorted colormap
1584 c = ((resolution & 0x07) << 5) | 0x00;
1585 if(stream->cmapSize != 0)
1587 globalBitsPP = binaryLog(stream->cmapSize);
1588 c |= 0x80;
1589 c |= globalBitsPP - 1;
1593 ** Is the global colormap optimized?
1595 if(optimize)
1596 c |= 0x08;
1597 PUTBYTE(c, fp);
1599 PUTBYTE(stream->background, fp);
1600 PUTBYTE(stream->aspectRatio, fp);
1602 putColorMap(fp, stream->cmapSize, stream->cmapData);
1604 for(cur = stream->data; cur != NULL; cur = cur->next)
1606 if(cur->type == gif_image)
1608 int bpp;
1610 putGif89Info(fp, &cur->info);
1612 PUTBYTE(0x2c, fp);
1613 PUTWORD(cur->x, fp);
1614 PUTWORD(cur->y, fp);
1615 PUTWORD(cur->width, fp);
1616 PUTWORD(cur->height, fp);
1618 c = cur->data.image.interlaced ? 0x40 : 0x00;
1619 if(cur->data.image.cmapSize != 0)
1621 bpp = binaryLog(cur->data.image.cmapSize);
1622 c |= 0x80;
1623 c |= bpp;
1625 else
1627 bpp = globalBitsPP;
1630 PUTBYTE(c, fp);
1632 putColorMap(fp, cur->data.image.cmapSize, cur->data.image.cmapData);
1634 putImage(fp, cur->data.image.interlaced, bpp, cur->width,
1635 cur->height, cur->data.image.data);
1637 else if(cur->type == gif_comment)
1639 PUTBYTE('!', fp);
1640 PUTBYTE(0xfe, fp);
1641 putDataBlocks(
1642 fp,
1643 cur->data.comment.len,
1644 reinterpret_cast<unsigned char *>(cur->data.comment.text));
1646 else if(cur->type == gif_text)
1648 putGif89Info(fp, &cur->info);
1650 PUTBYTE('!', fp);
1651 PUTBYTE(0x01, fp);
1653 PUTWORD(cur->x, fp);
1654 PUTWORD(cur->y, fp);
1655 PUTWORD(cur->width, fp);
1656 PUTWORD(cur->height, fp);
1658 PUTBYTE(cur->data.text.cellWidth, fp);
1659 PUTBYTE(cur->data.text.cellHeight, fp);
1660 PUTBYTE(cur->data.text.fg, fp);
1661 PUTBYTE(cur->data.text.bg, fp);
1663 putDataBlocks(
1664 fp,
1665 cur->data.text.len,
1666 reinterpret_cast<unsigned char *>(cur->data.text.text));
1671 ** Write termination
1673 PUTBYTE(';', fp);
1675 return GIF_FALSE;
1678 #ifdef __sgi
1679 #pragma reset woff 1209
1680 #endif
1682 /* */
1683 int GIFWrite(char *file, GIFStream *stream, int optimize)
1685 if(stream != NULL)
1687 FILE *fp = fopen(file, "wb");
1689 if(fp != NULL)
1691 int s = GIFWriteFP(fp, stream, optimize);
1692 fclose(fp);
1693 return s;
1697 return GIF_TRUE;
1700 /* */
1701 static void putColorMap(FILE *fp, int size, unsigned char data[GIF_MAXCOLORS][3])
1703 int i;
1705 for(i = 0; i < size; i++)
1707 PUTBYTE(data[i][0], fp);
1708 PUTBYTE(data[i][1], fp);
1709 PUTBYTE(data[i][2], fp);
1713 /* */
1714 static void putDataBlocks(FILE *fp, int size, unsigned char *data)
1716 int n;
1718 while(size > 0)
1720 n = size > 255 ? 255 : size;
1722 PUTBYTE(n, fp);
1723 fwrite(data, 1, n, fp);
1724 data += n;
1725 size -= n;
1728 PUTBYTE(0, fp); /* End Block */
1731 #ifdef __sgi
1732 #pragma set woff 1209
1733 #endif
1735 /* */
1736 static void putGif89Info(FILE *fp, GIF89info *info)
1738 unsigned char c;
1740 if(info->transparent == -1 &&
1741 info->delayTime == 0 &&
1742 info->inputFlag == 0 &&
1743 info->disposal == 0)
1744 return;
1746 PUTBYTE('!', fp);
1747 PUTBYTE(0xf9, fp);
1748 PUTBYTE(4, fp);
1749 c = (info->inputFlag ? 0x02 : 0x00) | ((info->disposal & 0x07) << 2) | ((info->transparent != -1) ? 0x01 : 0x00);
1750 PUTBYTE(c, fp);
1751 PUTWORD(info->delayTime, fp);
1752 PUTBYTE(info->transparent, fp);
1755 ** End
1757 PUTBYTE(0, fp);
1760 #ifdef __sgi
1761 #pragma reset woff 1209
1762 #endif
1764 /***************************************************************************
1766 * GIFCOMPR.C - GIF Image compression routines
1768 * Lempel-Ziv compression based on 'compress'. GIF modifications by
1769 * David Rowley (mgardi@watdcsu.waterloo.edu)
1771 ***************************************************************************/
1773 * General DEFINEs
1776 #define BITS 12
1778 #define HSIZE 5003 /* 80% occupancy */
1780 #ifdef NO_UCHAR
1781 typedef char char_type;
1782 #else /*NO_UCHAR*/
1783 typedef unsigned char char_type;
1784 #endif /*NO_UCHAR*/
1788 * GIF Image compression - modified 'compress'
1790 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
1792 * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
1793 * Jim McKie (decvax!mcvax!jim)
1794 * Steve Davies (decvax!vax135!petsd!peora!srd)
1795 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
1796 * James A. Woods (decvax!ihnp4!ames!jaw)
1797 * Joe Orost (decvax!vax135!petsd!joe)
1800 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
1801 static int n_bits; /* number of bits/code */
1802 static int maxbits; /* user settable max # bits/code */
1803 static code_int maxcode; /* maximum code, given n_bits */
1804 static code_int maxmaxcode; /* should NEVER generate this code */
1805 #define MAXCODE(n_bits) ((static_cast<code_int>(1) << (n_bits)) - 1)
1806 static count_int htab[HSIZE];
1807 static unsigned short codetab[HSIZE];
1808 #define HashTabOf(i) htab[i]
1809 #define CodeTabOf(i) codetab[i]
1811 static code_int hsize; /* for dynamic table sizing */
1813 static unsigned long cur_accum;
1814 static int cur_bits;
1817 * To save much memory, we overlay the table used by compress() with those
1818 * used by decompress(). The tab_prefix table is the same size and type
1819 * as the codetab. The tab_suffix table needs 2**BITS characters. We
1820 * get this from the beginning of htab. The output stack uses the rest
1821 * of htab, and contains characters. There is plenty of room for any
1822 * possible stack (stack used to be 8000 characters).
1824 #define tab_prefixof(i) CodeTabOf(i)
1825 #define tab_suffixof(i) ((char_type *) (htab))[i]
1826 #define de_stack ((char_type *) &tab_suffixof((code_int) 1 << BITS))
1827 static code_int free_ent; /* first unused entry */
1830 * block compression parameters -- after all codes are used up,
1831 * and compression rate changes, start over.
1833 static int clear_flg;
1835 // static int offset = 0;
1837 * compress stdin to stdout
1839 * Algorithm: use open addressing double hashing (no chaining) on the
1840 * prefix code / next character combination. We do a variant of Knuth's
1841 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1842 * secondary probe. Here, the modular division first probe is gives way
1843 * to a faster exclusive-or manipulation. Also do block compression with
1844 * an adaptive reset, whereby the code table is cleared when the compression
1845 * ratio decreases, but after the table fills. The variable-length output
1846 * codes are re-sized at this point, and a special CLEAR code is generated
1847 * for the decompressor. Late addition: construct the table according to
1848 * file size for noticeable speed improvement on small files. Please direct
1849 * questions about this implementation to ames!jaw.
1851 static int g_init_bits;
1852 static FILE *g_outfile;
1854 static int ClearCode;
1855 static int EOFCode;
1857 /* */
1859 #ifdef __sgi
1860 #pragma set woff 1209
1861 #endif
1863 static void putImage(FILE *fp, int interlaced, int bpp, int width, int height,
1864 unsigned char *data)
1866 // unsigned char *end = data + width * height;
1867 int left = interlaced ? width : width * height;
1868 int cury = 0, pass = 0;
1869 unsigned char *dp = data;
1870 long fcode;
1871 code_int v, i, ent, disp, hsize_reg;
1872 int c, hshift;
1874 // int skip = 8;
1875 if(bpp <= 1)
1877 g_init_bits = 3;
1878 PUTBYTE(2, fp);
1880 else
1882 g_init_bits = bpp + 1;
1883 PUTBYTE(bpp, fp);
1887 ** Set up the globals: g_init_bits - initial number of bits
1888 ** g_outfile - pointer to output file
1890 g_outfile = fp;
1893 ** Set up the necessary values
1895 // offset = 0;
1896 clear_flg = GIF_FALSE;
1897 maxbits = BITS;
1898 maxmaxcode = 1 << BITS;
1899 maxcode = MAXCODE(n_bits = g_init_bits);
1900 hsize = HSIZE;
1901 cur_accum = 0;
1902 cur_bits = 0;
1904 ClearCode = (1 << (g_init_bits - 1));
1905 EOFCode = ClearCode + 1;
1906 free_ent = ClearCode + 2;
1908 char_init(); /* clear the output accumulator */
1910 hshift = 0;
1911 for(fcode = long(hsize); fcode < 65536; fcode *= 2)
1912 ++hshift;
1913 hshift = 8 - hshift; /* set hash code range bound */
1915 hsize_reg = hsize;
1916 cl_hash(count_int(hsize)); /* clear hash table */
1918 output(code_int(ClearCode));
1920 ent = *dp++;
1923 again:
1925 ** Fetch the next pixel
1927 c = *dp++;
1928 if(--left == 0)
1930 if(interlaced)
1934 switch(pass)
1936 case 0:
1937 cury += 8;
1938 if(cury >= height)
1940 pass++;
1941 cury = 4;
1943 break;
1944 case 1:
1945 cury += 8;
1946 if(cury >= height)
1948 pass++;
1949 cury = 2;
1951 break;
1952 case 2:
1953 cury += 4;
1954 if(cury >= height)
1956 pass++;
1957 cury = 1;
1959 break;
1960 case 3:
1961 cury += 2;
1962 break;
1964 } while(pass < 3 && cury >= height);
1965 if(cury >= height)
1966 goto done;
1967 dp = data + cury * width;
1968 left = width;
1969 c = *dp++;
1971 else
1973 goto done;
1978 ** Now output it...
1980 fcode = long((long(c) << maxbits) + ent);
1982 i = ((code_int(c) << hshift) ^ ent); /* xor hashing */
1983 v = HashTabOf(i);
1985 if(v == fcode)
1987 ent = CodeTabOf(i);
1988 goto again;
1990 else if(v >= 0)
1993 ** secondary hash (after G. Knott)
1995 disp = hsize_reg - i;
1996 if(i == 0)
1997 disp = 1;
2000 if((i -= disp) < 0)
2001 i += hsize_reg;
2003 v = HashTabOf(i);
2004 if(v == fcode)
2006 ent = CodeTabOf(i);
2007 goto again;
2009 } while(v > 0);
2012 output(code_int(ent));
2013 ent = c;
2014 if(free_ent < maxmaxcode)
2016 CodeTabOf(i) = free_ent++; /* code -> hashtable */
2017 HashTabOf(i) = fcode;
2019 else
2021 cl_block();
2023 } while(1);
2024 done:
2026 ** Put out the final code.
2028 output(code_int(ent));
2029 output(code_int(EOFCode));
2032 ** End block byte
2034 PUTBYTE(0x00, fp);
2037 #ifdef __sgi
2038 #pragma reset woff 1209
2039 #endif
2041 /*****************************************************************
2042 * TAG( output )
2044 * Output the given code.
2045 * Inputs:
2046 * code: A n_bits-bit integer. If == -1, then EOF. This assumes
2047 * that n_bits =< (long)wordsize - 1.
2048 * Outputs:
2049 * Outputs code to the file.
2050 * Assumptions:
2051 * Chars are 8 bits long.
2052 * Algorithm:
2053 * Maintain a BITS character long buffer (so that 8 codes will
2054 * fit in it exactly). Use the VAX insv instruction to insert each
2055 * code in turn. When the buffer fills up empty it and start over.
2058 static unsigned long masks[] = { 0x0000,
2059 0x0001, 0x0003, 0x0007, 0x000F,
2060 0x001F, 0x003F, 0x007F, 0x00FF,
2061 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
2062 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
2064 static void output(code_int code)
2066 cur_accum &= masks[cur_bits];
2068 if(cur_bits > 0)
2070 cur_accum |= (long(code) << cur_bits);
2072 else
2073 cur_accum = code;
2075 cur_bits += n_bits;
2077 while(cur_bits >= 8)
2079 char_out(static_cast<unsigned int>(cur_accum & 0xff));
2080 cur_accum >>= 8;
2081 cur_bits -= 8;
2085 ** If the next entry is going to be too big for the code size,
2086 ** then increase it, if possible.
2088 if(free_ent > maxcode || clear_flg)
2090 if(clear_flg)
2092 maxcode = MAXCODE(n_bits = g_init_bits);
2093 clear_flg = GIF_FALSE;
2095 else
2097 ++n_bits;
2098 if(n_bits == maxbits)
2099 maxcode = maxmaxcode;
2100 else
2101 maxcode = MAXCODE(n_bits);
2105 if(code == EOFCode)
2108 ** At EOF, write the rest of the buffer.
2110 while(cur_bits > 0)
2112 char_out(static_cast<unsigned int>(cur_accum & 0xff));
2113 cur_accum >>= 8;
2114 cur_bits -= 8;
2117 flush_char();
2119 fflush(g_outfile);
2124 * Clear out the hash table
2126 static void cl_block(void)
2128 cl_hash(count_int(hsize));
2129 free_ent = ClearCode + 2;
2130 clear_flg = GIF_TRUE;
2132 output(code_int(ClearCode));
2135 /* */
2136 static void cl_hash(count_int hsizeIn) /* reset code table */
2138 int i;
2140 for(i = 0; i < hsizeIn; i++)
2141 htab[i] = -1;
2144 /******************************************************************************
2146 * GIF Specific routines
2148 ******************************************************************************/
2150 ** Number of characters so far in this 'packet'
2152 static int a_count;
2155 ** Define the storage for the packet accumulator
2157 static char accum[256];
2160 ** Set up the 'byte output' routine
2162 static void char_init(void)
2164 a_count = 0;
2168 ** Add a character to the end of the current packet, and if it is 254
2169 ** characters, flush the packet to disk.
2171 static void char_out(int c)
2173 accum[a_count++] = c;
2174 if(a_count == 255)
2175 flush_char();
2179 ** Flush the packet to disk, and reset the accumulator
2181 static void flush_char(void)
2183 if(a_count != 0)
2185 PUTBYTE(a_count, g_outfile);
2186 fwrite(accum, 1, a_count, g_outfile);
2187 a_count = 0;
2191 //--- GIF-WRITE END -----------------------------------------------------
2192 #endif