428
+ − 1 /******************************************************************************
+ − 2 * "Gif-Lib" - Yet another gif library. *
+ − 3 * *
+ − 4 * Written by: Gershon Elber IBM PC Ver 1.1, Aug. 1990 *
+ − 5 *******************************************************************************
+ − 6 * The kernel of the GIF Decoding process can be found here. *
+ − 7 *******************************************************************************
+ − 8 * History: *
+ − 9 * 16 Jun 89 - Version 1.0 by Gershon Elber. *
+ − 10 * 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
+ − 11 * 19 Feb 98 - Version 1.2 by Jareth Hein (Support for user specified I/O) *
+ − 12 ******************************************************************************/
+ − 13
442
+ − 14 #include <config.h>
+ − 15 #include "lisp.h"
428
+ − 16
442
+ − 17 #include "sysfile.h"
428
+ − 18
+ − 19 #include "gifrlib.h"
+ − 20
+ − 21 #define PROGRAM_NAME "GIFLIB"
+ − 22
+ − 23
+ − 24 static void DGifGetWord(GifFileType *GifFile, int *Word);
+ − 25 static void DGifSetupDecompress(GifFileType *GifFile);
+ − 26 static void DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
+ − 27 int LineLen);
+ − 28 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode);
+ − 29 static void DGifDecompressInput(GifFileType *GifFile, int *Code);
+ − 30 static void DGifBufferedInput(GifFileType *GifFile, GifByteType *NextByte);
+ − 31
+ − 32 /******************************************************************************
+ − 33 * Open a new gif file for read, given by its name. *
+ − 34 * Returns GifFileType pointer dynamically allocated which serves as the gif *
+ − 35 * info record. *
+ − 36 ******************************************************************************/
+ − 37 void DGifOpenFileName(GifFileType *GifFile, const char *FileName)
+ − 38 {
+ − 39 FILE *f;
+ − 40
+ − 41 if ((f = fopen(FileName,
442
+ − 42 #ifdef WIN32_NATIVE
428
+ − 43 "rb"
+ − 44 #else
+ − 45 "r"
442
+ − 46 #endif /* WIN32_NATIVE */
428
+ − 47 )) == NULL)
+ − 48 GifInternError(GifFile, D_GIF_ERR_OPEN_FAILED);
+ − 49
+ − 50 GifStdIOInit(GifFile, f, -1);
+ − 51 DGifInitRead(GifFile);
+ − 52 }
+ − 53
+ − 54 /******************************************************************************
+ − 55 * Update a new gif file, given its file handle. *
+ − 56 * Returns GifFileType pointer dynamically allocated which serves as the gif *
+ − 57 * info record. *
+ − 58 ******************************************************************************/
+ − 59 void DGifOpenFileHandle(GifFileType *GifFile, int FileHandle)
+ − 60 {
+ − 61 FILE *f;
+ − 62
442
+ − 63 #ifdef WIN32_NATIVE
428
+ − 64 setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
+ − 65 f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
+ − 66 setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);/* And inc. stream buffer.*/
+ − 67 #else
+ − 68 f = fdopen(FileHandle, "r"); /* Make it into a stream: */
442
+ − 69 #endif /* WIN32_NATIVE */
428
+ − 70
+ − 71 GifStdIOInit(GifFile, f, -1);
+ − 72 DGifInitRead(GifFile);
+ − 73 }
+ − 74
+ − 75 /******************************************************************************
+ − 76 * Update a new gif file, given its file handle. *
+ − 77 * Returns GifFileType pointer dynamically allocated which serves as the gif *
+ − 78 * info record. _GifError is cleared if succesfull. *
+ − 79 ******************************************************************************/
+ − 80 void DGifInitRead(GifFileType *GifFile)
+ − 81 {
+ − 82 GifByteType Buf[GIF_STAMP_LEN+1];
+ − 83 GifFilePrivateType *Private;
+ − 84
+ − 85 if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
+ − 86 == NULL) {
+ − 87 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
+ − 88 }
+ − 89 memset(Private, '\0', sizeof(GifFilePrivateType));
+ − 90 GifFile->Private = (VoidPtr) Private;
+ − 91
+ − 92 Private->FileState = 0; /* Make sure bit 0 = 0 (File open for read). */
+ − 93
+ − 94 /* Lets see if this is a GIF file: */
+ − 95 GifRead(Buf, GIF_STAMP_LEN, GifFile);
+ − 96
+ − 97 /* The GIF Version number is ignored at this time. Maybe we should do */
+ − 98 /* something more useful with it. */
+ − 99 Buf[GIF_STAMP_LEN] = 0;
+ − 100 if (strncmp(GIF_STAMP, (const char *) Buf, GIF_VERSION_POS) != 0) {
+ − 101 GifInternError(GifFile, D_GIF_ERR_NOT_GIF_FILE);
+ − 102 }
+ − 103
+ − 104 DGifGetScreenDesc(GifFile);
+ − 105 }
+ − 106
+ − 107 /******************************************************************************
+ − 108 * This routine should be called before any other DGif calls. Note that *
+ − 109 * this routine is called automatically from DGif file open routines. *
+ − 110 ******************************************************************************/
+ − 111 void DGifGetScreenDesc(GifFileType *GifFile)
+ − 112 {
+ − 113 int i, BitsPerPixel;
+ − 114 GifByteType Buf[3];
+ − 115 GifFilePrivateType *Private = (GifFilePrivateType*) GifFile->Private;
+ − 116
+ − 117 if (!IS_READABLE(Private)) {
+ − 118 /* This file was NOT open for reading: */
+ − 119 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 120 }
+ − 121
+ − 122 /* Put the screen descriptor into the file: */
+ − 123 DGifGetWord(GifFile, &GifFile->SWidth);
+ − 124 DGifGetWord(GifFile, &GifFile->SHeight);
+ − 125
+ − 126 GifRead(Buf, 3, GifFile);
+ − 127 GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
+ − 128 BitsPerPixel = (Buf[0] & 0x07) + 1;
+ − 129 GifFile->SBackGroundColor = Buf[1];
+ − 130 if (Buf[0] & 0x80) { /* Do we have global color map? */
+ − 131
+ − 132 GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
+ − 133
+ − 134 /* Get the global color map: */
+ − 135 for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
+ − 136 GifRead(Buf, 3, GifFile);
+ − 137 GifFile->SColorMap->Colors[i].Red = Buf[0];
+ − 138 GifFile->SColorMap->Colors[i].Green = Buf[1];
+ − 139 GifFile->SColorMap->Colors[i].Blue = Buf[2];
+ − 140 }
+ − 141 } else {
+ − 142 /* We should always have a colormap */
+ − 143 GifFile->SColorMap = MakeMapObject(2, NULL);
+ − 144 GifFile->SColorMap->Colors[0].Red = 0;
+ − 145 GifFile->SColorMap->Colors[0].Green = 0;
+ − 146 GifFile->SColorMap->Colors[0].Blue = 0;
+ − 147 GifFile->SColorMap->Colors[1].Red = 0xff;
+ − 148 GifFile->SColorMap->Colors[1].Green = 0xff;
+ − 149 GifFile->SColorMap->Colors[1].Blue = 0xff;
+ − 150 }
+ − 151 }
+ − 152
+ − 153 /******************************************************************************
+ − 154 * This routine should be called before any attemp to read an image. *
+ − 155 ******************************************************************************/
+ − 156 void DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type)
+ − 157 {
+ − 158 GifByteType Buf;
+ − 159 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 160
+ − 161 if (!IS_READABLE(Private)) {
+ − 162 /* This file was NOT open for reading: */
+ − 163 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 164 }
+ − 165
+ − 166 GifRead(&Buf, 1, GifFile);
+ − 167
+ − 168 switch (Buf) {
+ − 169 case ',':
+ − 170 *Type = IMAGE_DESC_RECORD_TYPE;
+ − 171 break;
+ − 172 case '!':
+ − 173 *Type = EXTENSION_RECORD_TYPE;
+ − 174 break;
+ − 175 case ';':
+ − 176 *Type = TERMINATE_RECORD_TYPE;
+ − 177 break;
+ − 178 default:
+ − 179 *Type = UNDEFINED_RECORD_TYPE;
+ − 180 GifInternError(GifFile, D_GIF_ERR_WRONG_RECORD);
+ − 181 }
+ − 182 }
+ − 183
+ − 184 /******************************************************************************
+ − 185 * This routine should be called before any attemp to read an image. *
+ − 186 * Note it is assumed the Image desc. header (',') has been read. *
+ − 187 ******************************************************************************/
+ − 188 void DGifGetImageDesc(GifFileType *GifFile)
+ − 189 {
+ − 190 int i, BitsPerPixel;
+ − 191 GifByteType Buf[3];
+ − 192 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 193
+ − 194 if (!IS_READABLE(Private)) {
+ − 195 /* This file was NOT open for reading: */
+ − 196 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 197 }
+ − 198
+ − 199 DGifGetWord(GifFile, &GifFile->Image.Left);
+ − 200 DGifGetWord(GifFile, &GifFile->Image.Top);
+ − 201 DGifGetWord(GifFile, &GifFile->Image.Width);
+ − 202 DGifGetWord(GifFile, &GifFile->Image.Height);
+ − 203
+ − 204 GifRead(Buf, 1, GifFile);
+ − 205 BitsPerPixel = (Buf[0] & 0x07) + 1;
+ − 206 GifFile->Image.Interlace = (Buf[0] & 0x40);
+ − 207 if (Buf[0] & 0x80) { /* Does this image have local color map? */
+ − 208
+ − 209 if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL)
+ − 210 FreeMapObject(GifFile->Image.ColorMap);
+ − 211
+ − 212 GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
+ − 213
+ − 214 /* Get the image local color map: */
+ − 215 for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
+ − 216 GifRead(Buf, 3, GifFile);
+ − 217 GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
+ − 218 GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
+ − 219 GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
+ − 220 }
+ − 221 }
+ − 222
+ − 223 if (GifFile->SavedImages) {
+ − 224 SavedImage *sp;
+ − 225
+ − 226 if ((GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
+ − 227 sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) {
+ − 228 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
+ − 229 }
+ − 230
+ − 231 sp = &GifFile->SavedImages[GifFile->ImageCount];
+ − 232 memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
+ − 233 if (GifFile->Image.ColorMap)
+ − 234 {
+ − 235 sp->ImageDesc.ColorMap =
+ − 236 MakeMapObject (GifFile->Image.ColorMap->ColorCount,
+ − 237 GifFile->Image.ColorMap->Colors);
+ − 238 }
+ − 239 sp->RasterBits = NULL;
+ − 240 sp->ExtensionBlockCount = 0;
+ − 241 sp->ExtensionBlocks = (ExtensionBlock *)NULL;
+ − 242 }
+ − 243
+ − 244 GifFile->ImageCount++;
+ − 245
+ − 246 Private->PixelCount = (long) GifFile->Image.Width *
+ − 247 (long) GifFile->Image.Height;
+ − 248
+ − 249 DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */
+ − 250 }
+ − 251
+ − 252 /******************************************************************************
+ − 253 * Get one full scanned line (Line) of length LineLen from GIF file. *
+ − 254 ******************************************************************************/
+ − 255 void DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
+ − 256 {
+ − 257 GifByteType *Dummy;
+ − 258 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 259
+ − 260 if (!IS_READABLE(Private)) {
+ − 261 /* This file was NOT open for reading: */
+ − 262 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 263 }
+ − 264
+ − 265 if (!LineLen) LineLen = GifFile->Image.Width;
+ − 266
442
+ − 267 #if defined(WIN32_NATIVE) || defined(__GNUC__)
428
+ − 268 if ((Private->PixelCount -= LineLen) > 0xffff0000UL)
+ − 269 #else
+ − 270 if ((Private->PixelCount -= LineLen) > 0xffff0000)
442
+ − 271 #endif /* WIN32_NATIVE */
428
+ − 272 {
+ − 273 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
+ − 274 }
+ − 275
+ − 276 DGifDecompressLine(GifFile, Line, LineLen);
+ − 277 if (Private->PixelCount == 0) {
+ − 278 /* We probably would not be called any more, so lets clean */
+ − 279 /* everything before we return: need to flush out all rest of */
+ − 280 /* image until empty block (size 0) detected. We use GetCodeNext.*/
+ − 281 do
+ − 282 DGifGetCodeNext(GifFile, &Dummy);
+ − 283 while (Dummy != NULL);
+ − 284 }
+ − 285 }
+ − 286
+ − 287 /******************************************************************************
+ − 288 * Put one pixel (Pixel) into GIF file. *
+ − 289 ******************************************************************************/
+ − 290 void DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)
+ − 291 {
+ − 292 GifByteType *Dummy;
+ − 293 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 294
+ − 295 if (!IS_READABLE(Private)) {
+ − 296 /* This file was NOT open for reading: */
+ − 297 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 298 }
+ − 299
442
+ − 300 #if defined(WIN32_NATIVE) || defined(__GNUC__)
428
+ − 301 if (--Private->PixelCount > 0xffff0000UL)
+ − 302 #else
+ − 303 if (--Private->PixelCount > 0xffff0000)
442
+ − 304 #endif /* WIN32_NATIVE */
428
+ − 305 {
+ − 306 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
+ − 307 }
+ − 308
+ − 309 DGifDecompressLine(GifFile, &Pixel, 1);
+ − 310 if (Private->PixelCount == 0) {
+ − 311 /* We probably would not be called any more, so lets clean */
+ − 312 /* everything before we return: need to flush out all rest of */
+ − 313 /* image until empty block (size 0) detected. We use GetCodeNext.*/
+ − 314 do
+ − 315 DGifGetCodeNext(GifFile, &Dummy);
+ − 316 while (Dummy != NULL);
+ − 317 }
+ − 318 }
+ − 319
+ − 320 /******************************************************************************
+ − 321 * Get an extension block (see GIF manual) from gif file. This routine only *
+ − 322 * returns the first data block, and DGifGetExtensionNext shouldbe called *
+ − 323 * after this one until NULL extension is returned. *
+ − 324 * The Extension should NOT be freed by the user (not dynamically allocated).*
+ − 325 * Note it is assumed the Extension desc. header ('!') has been read. *
+ − 326 ******************************************************************************/
+ − 327 void DGifGetExtension(GifFileType *GifFile, int *ExtCode,
+ − 328 GifByteType **Extension)
+ − 329 {
+ − 330 GifByteType Buf;
+ − 331 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 332
+ − 333 if (!IS_READABLE(Private)) {
+ − 334 /* This file was NOT open for reading: */
+ − 335 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 336 }
+ − 337
+ − 338 GifRead(&Buf, 1, GifFile);
+ − 339 *ExtCode = Buf;
+ − 340
+ − 341 DGifGetExtensionNext(GifFile, Extension);
+ − 342 }
+ − 343
+ − 344 /******************************************************************************
+ − 345 * Get a following extension block (see GIF manual) from gif file. This *
+ − 346 * routine sould be called until NULL Extension is returned. *
+ − 347 * The Extension should NOT be freed by the user (not dynamically allocated).*
+ − 348 ******************************************************************************/
+ − 349 void DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension)
+ − 350 {
+ − 351 GifByteType Buf;
+ − 352 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 353
+ − 354 GifRead(&Buf, 1, GifFile);
+ − 355 if (Buf > 0) {
+ − 356 *Extension = Private->Buf; /* Use private unused buffer. */
+ − 357 (*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
+ − 358 GifRead(&((*Extension)[1]), Buf, GifFile);
+ − 359 }
+ − 360 else
+ − 361 *Extension = NULL;
+ − 362 }
+ − 363
+ − 364 /******************************************************************************
+ − 365 * This routine should be called second to last, to close the GIF file. *
+ − 366 ******************************************************************************/
+ − 367 int DGifCloseFile(GifFileType *GifFile)
+ − 368 {
+ − 369 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
+ − 370
+ − 371 if (GifFile == NULL) return -1;
+ − 372
+ − 373 if (!IS_READABLE(Private))
+ − 374 {
+ − 375 /* This file was NOT open for reading: */
+ − 376 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 377 }
+ − 378
+ − 379 if (GifClose (GifFile))
+ − 380 {
+ − 381 GifInternError(GifFile, D_GIF_ERR_CLOSE_FAILED);
+ − 382 }
+ − 383 return 0;
+ − 384 }
+ − 385
+ − 386 /******************************************************************************
+ − 387 * Get 2 bytes (word) from the given file: *
+ − 388 ******************************************************************************/
+ − 389 static void DGifGetWord(GifFileType *GifFile, int *Word)
+ − 390 {
+ − 391 unsigned char c[2];
+ − 392
+ − 393 GifRead(c, 2, GifFile);
+ − 394
+ − 395 *Word = (((unsigned int) c[1]) << 8) + c[0];
+ − 396 }
+ − 397
+ − 398 /******************************************************************************
+ − 399 * Get the image code in compressed form. his routine can be called if the *
+ − 400 * information needed to be piped out as is. Obviously this is much faster *
+ − 401 * than decoding and encoding again. This routine should be followed by calls *
+ − 402 * to DGifGetCodeNext, until NULL block is returned. *
+ − 403 * The block should NOT be freed by the user (not dynamically allocated). *
+ − 404 ******************************************************************************/
+ − 405 void DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)
+ − 406 {
+ − 407 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 408
+ − 409 if (!IS_READABLE(Private)) {
+ − 410 /* This file was NOT open for reading: */
+ − 411 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 412 }
+ − 413
+ − 414 *CodeSize = Private->BitsPerPixel;
+ − 415
+ − 416 DGifGetCodeNext(GifFile, CodeBlock);
+ − 417 }
+ − 418
+ − 419 /******************************************************************************
+ − 420 * Continue to get the image code in compressed form. This routine should be *
+ − 421 * called until NULL block is returned. *
+ − 422 * The block should NOT be freed by the user (not dynamically allocated). *
+ − 423 ******************************************************************************/
+ − 424 void DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
+ − 425 {
+ − 426 GifByteType Buf;
+ − 427 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 428
+ − 429 GifRead(&Buf, 1, GifFile);
+ − 430
+ − 431 if (Buf > 0) {
+ − 432 *CodeBlock = Private->Buf; /* Use private unused buffer. */
+ − 433 (*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
+ − 434 GifRead(&((*CodeBlock)[1]), Buf, GifFile);
+ − 435 }
+ − 436 else {
+ − 437 *CodeBlock = NULL;
+ − 438 Private->Buf[0] = 0; /* Make sure the buffer is empty! */
+ − 439 Private->PixelCount = 0; /* And local info. indicate image read. */
+ − 440 }
+ − 441
+ − 442 }
+ − 443
+ − 444 /******************************************************************************
+ − 445 * Setup the LZ decompression for this image: *
+ − 446 ******************************************************************************/
+ − 447 static void DGifSetupDecompress(GifFileType *GifFile)
+ − 448 {
+ − 449 int i, BitsPerPixel;
+ − 450 GifByteType CodeSize;
+ − 451 unsigned int *Prefix;
+ − 452 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 453
+ − 454 GifRead(&CodeSize, 1, GifFile); /* Read Code size from file. */
+ − 455 BitsPerPixel = CodeSize;
+ − 456
+ − 457 Private->Buf[0] = 0; /* Input Buffer empty. */
+ − 458 Private->BitsPerPixel = BitsPerPixel;
+ − 459 Private->ClearCode = (1 << BitsPerPixel);
+ − 460 Private->EOFCode = Private->ClearCode + 1;
+ − 461 Private->RunningCode = Private->EOFCode + 1;
+ − 462 Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
+ − 463 Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
+ − 464 Private->StackPtr = 0; /* No pixels on the pixel stack. */
+ − 465 Private->LastCode = NO_SUCH_CODE;
+ − 466 Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
+ − 467 Private->CrntShiftDWord = 0;
+ − 468
+ − 469 Prefix = Private->Prefix;
+ − 470 for (i = 0; i <= LZ_MAX_CODE; i++) Prefix[i] = NO_SUCH_CODE;
+ − 471 }
+ − 472
+ − 473 /******************************************************************************
+ − 474 * The LZ decompression routine: *
+ − 475 * This version decompress the given gif file into Line of length LineLen. *
+ − 476 * This routine can be called few times (one per scan line, for example), in *
+ − 477 * order the complete the whole image. *
+ − 478 ******************************************************************************/
+ − 479 static void DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
+ − 480 int LineLen)
+ − 481 {
+ − 482 int i = 0, j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
+ − 483 GifByteType *Stack, *Suffix;
+ − 484 unsigned int *Prefix;
+ − 485 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 486
+ − 487 StackPtr = Private->StackPtr;
+ − 488 Prefix = Private->Prefix;
+ − 489 Suffix = Private->Suffix;
+ − 490 Stack = Private->Stack;
+ − 491 EOFCode = Private->EOFCode;
+ − 492 ClearCode = Private->ClearCode;
+ − 493 LastCode = Private->LastCode;
+ − 494
+ − 495 CrntPrefix = 0;
+ − 496 if (StackPtr != 0) {
+ − 497 /* Let pop the stack off before continueing to read the gif file: */
+ − 498 while (StackPtr != 0 && i < LineLen) Line[i++] = Stack[--StackPtr];
+ − 499 }
+ − 500
+ − 501 while (i < LineLen) { /* Decode LineLen items. */
+ − 502 DGifDecompressInput(GifFile, &CrntCode);
+ − 503
+ − 504 if (CrntCode == EOFCode) {
+ − 505 /* Note however that usually we will not be here as we will stop */
+ − 506 /* decoding as soon as we got all the pixel, or EOF code will */
+ − 507 /* not be read at all, and DGifGetLine/Pixel clean everything. */
+ − 508 if (i != LineLen - 1 || Private->PixelCount != 0) {
+ − 509 GifInternError(GifFile, D_GIF_ERR_EOF_TOO_SOON);
+ − 510 }
+ − 511 i++;
+ − 512 }
+ − 513 else if (CrntCode == ClearCode) {
+ − 514 /* We need to start over again: */
+ − 515 for (j = 0; j <= LZ_MAX_CODE; j++) Prefix[j] = NO_SUCH_CODE;
+ − 516 Private->RunningCode = Private->EOFCode + 1;
+ − 517 Private->RunningBits = Private->BitsPerPixel + 1;
+ − 518 Private->MaxCode1 = 1 << Private->RunningBits;
+ − 519 LastCode = Private->LastCode = NO_SUCH_CODE;
+ − 520 }
+ − 521 else {
+ − 522 /* Its regular code - if in pixel range simply add it to output */
+ − 523 /* stream, otherwise trace to codes linked list until the prefix */
+ − 524 /* is in pixel range: */
+ − 525 if (CrntCode < ClearCode) {
+ − 526 /* This is simple - its pixel scalar, so add it to output: */
+ − 527 Line[i++] = CrntCode;
+ − 528 }
+ − 529 else {
+ − 530 /* Its a code to needed to be traced: trace the linked list */
+ − 531 /* until the prefix is a pixel, while pushing the suffix */
+ − 532 /* pixels on our stack. If we done, pop the stack in reverse */
+ − 533 /* (thats what stack is good for!) order to output. */
+ − 534 if (Prefix[CrntCode] == NO_SUCH_CODE) {
+ − 535 /* Only allowed if CrntCode is exactly the running code: */
+ − 536 /* In that case CrntCode = XXXCode, CrntCode or the */
+ − 537 /* prefix code is last code and the suffix char is */
+ − 538 /* exactly the prefix of last code! */
+ − 539 if (CrntCode == Private->RunningCode - 2) {
+ − 540 CrntPrefix = LastCode;
+ − 541 Suffix[Private->RunningCode - 2] =
+ − 542 Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
+ − 543 LastCode, ClearCode);
+ − 544 }
+ − 545 else {
+ − 546 GifInternError(GifFile, D_GIF_ERR_IMAGE_DEFECT);
+ − 547 }
+ − 548 }
+ − 549 else
+ − 550 CrntPrefix = CrntCode;
+ − 551
+ − 552 /* Now (if image is O.K.) we should not get an NO_SUCH_CODE */
+ − 553 /* During the trace. As we might loop forever, in case of */
+ − 554 /* defective image, we count the number of loops we trace */
+ − 555 /* and stop if we got LZ_MAX_CODE. obviously we can not */
+ − 556 /* loop more than that. */
+ − 557 j = 0;
+ − 558 while (j++ <= LZ_MAX_CODE &&
+ − 559 CrntPrefix > ClearCode &&
+ − 560 CrntPrefix <= LZ_MAX_CODE) {
+ − 561 Stack[StackPtr++] = Suffix[CrntPrefix];
+ − 562 CrntPrefix = Prefix[CrntPrefix];
+ − 563 }
+ − 564 if (j >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {
+ − 565 GifInternError(GifFile, D_GIF_ERR_IMAGE_DEFECT);
+ − 566 }
+ − 567 /* Push the last character on stack: */
+ − 568 Stack[StackPtr++] = CrntPrefix;
+ − 569
+ − 570 /* Now lets pop all the stack into output: */
+ − 571 while (StackPtr != 0 && i < LineLen)
+ − 572 Line[i++] = Stack[--StackPtr];
+ − 573 }
+ − 574 if (LastCode != NO_SUCH_CODE) {
+ − 575 Prefix[Private->RunningCode - 2] = LastCode;
+ − 576
+ − 577 if (CrntCode == Private->RunningCode - 2) {
+ − 578 /* Only allowed if CrntCode is exactly the running code: */
+ − 579 /* In that case CrntCode = XXXCode, CrntCode or the */
+ − 580 /* prefix code is last code and the suffix char is */
+ − 581 /* exactly the prefix of last code! */
+ − 582 Suffix[Private->RunningCode - 2] =
+ − 583 DGifGetPrefixChar(Prefix, LastCode, ClearCode);
+ − 584 }
+ − 585 else {
+ − 586 Suffix[Private->RunningCode - 2] =
+ − 587 DGifGetPrefixChar(Prefix, CrntCode, ClearCode);
+ − 588 }
+ − 589 }
+ − 590 LastCode = CrntCode;
+ − 591 }
+ − 592 }
+ − 593
+ − 594 Private->LastCode = LastCode;
+ − 595 Private->StackPtr = StackPtr;
+ − 596 }
+ − 597
+ − 598 /******************************************************************************
+ − 599 * Routine to trace the Prefixes linked list until we get a prefix which is *
+ − 600 * not code, but a pixel value (less than ClearCode). Returns that pixel value.*
+ − 601 * If image is defective, we might loop here forever, so we limit the loops to *
+ − 602 * the maximum possible if image O.k. - LZ_MAX_CODE times. *
+ − 603 ******************************************************************************/
+ − 604 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode)
+ − 605 {
+ − 606 int i = 0;
+ − 607
+ − 608 while (Code > ClearCode && i++ <= LZ_MAX_CODE) Code = Prefix[Code];
+ − 609 return Code;
+ − 610 }
+ − 611
+ − 612 /******************************************************************************
+ − 613 * Interface for accessing the LZ codes directly. Set Code to the real code *
+ − 614 * (12bits), or to -1 if EOF code is returned. *
+ − 615 ******************************************************************************/
+ − 616 void DGifGetLZCodes(GifFileType *GifFile, int *Code)
+ − 617 {
+ − 618 GifByteType *CodeBlock;
+ − 619 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 620
+ − 621 if (!IS_READABLE(Private)) {
+ − 622 /* This file was NOT open for reading: */
+ − 623 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
+ − 624 }
+ − 625
+ − 626 DGifDecompressInput(GifFile, Code);
+ − 627
+ − 628 if (*Code == Private->EOFCode) {
+ − 629 /* Skip rest of codes (hopefully only NULL terminating block): */
+ − 630 do
+ − 631 DGifGetCodeNext(GifFile, &CodeBlock);
+ − 632 while (CodeBlock != NULL);
+ − 633
+ − 634 *Code = -1;
+ − 635 }
+ − 636 else if (*Code == Private->ClearCode) {
+ − 637 /* We need to start over again: */
+ − 638 Private->RunningCode = Private->EOFCode + 1;
+ − 639 Private->RunningBits = Private->BitsPerPixel + 1;
+ − 640 Private->MaxCode1 = 1 << Private->RunningBits;
+ − 641 }
+ − 642 }
+ − 643
+ − 644 /******************************************************************************
+ − 645 * The LZ decompression input routine: *
+ − 646 * This routine is responsable for the decompression of the bit stream from *
+ − 647 * 8 bits (bytes) packets, into the real codes. *
+ − 648 * Returns GIF_OK if read succesfully. *
+ − 649 ******************************************************************************/
+ − 650 static void DGifDecompressInput(GifFileType *GifFile, int *Code)
+ − 651 {
+ − 652 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 653 GifByteType NextByte;
+ − 654 static unsigned int CodeMasks[] = {
+ − 655 0x0000, 0x0001, 0x0003, 0x0007,
+ − 656 0x000f, 0x001f, 0x003f, 0x007f,
+ − 657 0x00ff, 0x01ff, 0x03ff, 0x07ff,
+ − 658 0x0fff
+ − 659 };
+ − 660
+ − 661 while (Private->CrntShiftState < Private->RunningBits) {
+ − 662 /* Needs to get more bytes from input stream for next code: */
+ − 663 DGifBufferedInput(GifFile, &NextByte);
+ − 664 Private->CrntShiftDWord |=
+ − 665 ((unsigned long) NextByte) << Private->CrntShiftState;
+ − 666 Private->CrntShiftState += 8;
+ − 667 }
+ − 668 *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
+ − 669
+ − 670 Private->CrntShiftDWord >>= Private->RunningBits;
+ − 671 Private->CrntShiftState -= Private->RunningBits;
+ − 672
+ − 673 /* If code cannt fit into RunningBits bits, must raise its size. Note */
+ − 674 /* however that codes above 4095 are used for special signaling. */
+ − 675 if (++Private->RunningCode > Private->MaxCode1 &&
+ − 676 Private->RunningBits < LZ_BITS) {
+ − 677 Private->MaxCode1 <<= 1;
+ − 678 Private->RunningBits++;
+ − 679 }
+ − 680 }
+ − 681
+ − 682 /******************************************************************************
+ − 683 * This routines read one gif data block at a time and buffers it internally *
+ − 684 * so that the decompression routine could access it. *
+ − 685 * The routine returns the next byte from its internal buffer (or read next *
+ − 686 * block in if buffer empty) *
+ − 687 ******************************************************************************/
+ − 688 static void DGifBufferedInput(GifFileType *GifFile, GifByteType *NextByte)
+ − 689 {
+ − 690 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+ − 691 GifByteType *Buf = Private->Buf;
+ − 692
+ − 693 if (Buf[0] == 0) {
+ − 694 /* Needs to read the next buffer - this one is empty: */
+ − 695 GifRead(Buf, 1, GifFile);
+ − 696 GifRead((Buf + 1), Buf[0], GifFile);
+ − 697 *NextByte = Buf[1];
+ − 698 Buf[1] = 2; /* We use now the second place as last char read! */
+ − 699 Buf[0]--;
+ − 700 }
+ − 701 else {
+ − 702 *NextByte = Buf[Buf[1]++];
+ − 703 Buf[0]--;
+ − 704 }
+ − 705 }
+ − 706
+ − 707 /******************************************************************************
+ − 708 * This routine reads an entire GIF into core, hanging all its state info off *
+ − 709 * the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle() *
+ − 710 * first to initialize I/O. Its inverse is EGifSpew(). *
+ − 711 ******************************************************************************/
+ − 712 void DGifSlurp(GifFileType *GifFile)
+ − 713 {
+ − 714 int ImageSize;
+ − 715 GifRecordType RecordType;
+ − 716 SavedImage *sp;
+ − 717 GifByteType *ExtData;
+ − 718
+ − 719 /* Some versions of malloc dislike 0-length requests */
+ − 720 GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
+ − 721 memset(GifFile->SavedImages, 0, sizeof(SavedImage));
+ − 722 sp = &GifFile->SavedImages[0];
+ − 723
+ − 724 do {
+ − 725 DGifGetRecordType(GifFile, &RecordType);
+ − 726
+ − 727 switch (RecordType) {
+ − 728 case IMAGE_DESC_RECORD_TYPE:
+ − 729 DGifGetImageDesc(GifFile);
+ − 730
+ − 731 sp = &GifFile->SavedImages[GifFile->ImageCount-1];
+ − 732 ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
+ − 733
+ − 734 sp->RasterBits
+ − 735 = (GifPixelType*) malloc (ImageSize * sizeof(GifPixelType));
+ − 736
+ − 737 DGifGetLine(GifFile, sp->RasterBits, ImageSize);
+ − 738 break;
+ − 739
+ − 740 case EXTENSION_RECORD_TYPE:
+ − 741 DGifGetExtension(GifFile,&sp->Function,&ExtData);
+ − 742
2062
+ − 743 while (ExtData != NULL) {
428
+ − 744 if (AddExtensionBlock(sp, ExtData[0], ExtData+1) == GIF_ERROR)
+ − 745 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
+ − 746 DGifGetExtensionNext(GifFile, &ExtData);
2062
+ − 747 }
428
+ − 748 break;
+ − 749
+ − 750 case TERMINATE_RECORD_TYPE:
+ − 751 break;
+ − 752
+ − 753 default: /* Should be trapped by DGifGetRecordType */
+ − 754 break;
+ − 755 }
+ − 756 } while (RecordType != TERMINATE_RECORD_TYPE);
+ − 757 }
+ − 758
+ − 759 /******************************************************************************
+ − 760 * Extension record functions *
+ − 761 ******************************************************************************/
+ − 762
+ − 763 void MakeExtension(SavedImage *New, int Function)
+ − 764 {
+ − 765 New->Function = Function;
+ − 766 /*
+ − 767 * Someday we might have to deal with multiple extensions.
+ − 768 */
+ − 769 }
+ − 770
+ − 771 int AddExtensionBlock(SavedImage *New, int Len, GifByteType *data)
+ − 772 {
+ − 773 int size;
+ − 774 ExtensionBlock *ep;
+ − 775
+ − 776 if (New->ExtensionBlocks == NULL)
+ − 777 New->ExtensionBlocks = (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
+ − 778 else
+ − 779 New->ExtensionBlocks =
+ − 780 (ExtensionBlock *)realloc(New->ExtensionBlocks,
+ − 781 sizeof(ExtensionBlock) * (New->ExtensionBlockCount + 1));
+ − 782
+ − 783 if (New->ExtensionBlocks == NULL)
+ − 784 return(GIF_ERROR);
+ − 785
+ − 786 ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
+ − 787 ep->ByteCount = Len;
+ − 788 size = Len * sizeof(GifByteType);
+ − 789 ep->Bytes = (GifByteType *)malloc(size);
+ − 790 memcpy(ep->Bytes, data, size);
+ − 791 return(GIF_OK);
+ − 792 }
+ − 793
+ − 794 void FreeExtension(SavedImage *Image)
+ − 795 {
+ − 796 ExtensionBlock *ep;
+ − 797
+ − 798 for (ep = Image->ExtensionBlocks;
+ − 799 ep < Image->ExtensionBlocks + Image->ExtensionBlockCount;
+ − 800 ep++)
+ − 801 (void) free((char *)ep->Bytes);
+ − 802 free((char *)Image->ExtensionBlocks);
+ − 803 Image->ExtensionBlocks = NULL;
+ − 804 }
+ − 805
+ − 806 /******************************************************************************
+ − 807 * Image block allocation functions *
+ − 808 ******************************************************************************/
+ − 809 SavedImage *MakeSavedImage(GifFileType *GifFile, SavedImage *CopyFrom)
+ − 810 /*
+ − 811 * Append an image block to the SavedImages array
+ − 812 */
+ − 813 {
+ − 814 SavedImage *sp;
+ − 815
+ − 816 if (GifFile->SavedImages == NULL)
+ − 817 GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
+ − 818 else
+ − 819 GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
+ − 820 sizeof(SavedImage) * (GifFile->ImageCount+1));
+ − 821
+ − 822 if (GifFile->SavedImages == NULL)
+ − 823 return((SavedImage *)NULL);
+ − 824 else
+ − 825 {
+ − 826 sp = &GifFile->SavedImages[GifFile->ImageCount++];
+ − 827 memset((char *)sp, '\0', sizeof(SavedImage));
+ − 828
+ − 829 if (CopyFrom)
+ − 830 {
+ − 831 memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
+ − 832
+ − 833 /*
+ − 834 * Make our own allocated copies of the heap fields in the
+ − 835 * copied record. This guards against potential aliasing
+ − 836 * problems.
+ − 837 */
+ − 838
+ − 839 /* first, the local color map */
+ − 840 if (sp->ImageDesc.ColorMap)
+ − 841 sp->ImageDesc.ColorMap =
+ − 842 MakeMapObject(CopyFrom->ImageDesc.ColorMap->ColorCount,
+ − 843 CopyFrom->ImageDesc.ColorMap->Colors);
+ − 844
+ − 845 /* next, the raster */
+ − 846 sp->RasterBits = (GifPixelType *) malloc(sizeof(GifPixelType)
+ − 847 * CopyFrom->ImageDesc.Height
+ − 848 * CopyFrom->ImageDesc.Width);
+ − 849 memcpy(sp->RasterBits,
+ − 850 CopyFrom->RasterBits,
+ − 851 sizeof(GifPixelType)
+ − 852 * CopyFrom->ImageDesc.Height
+ − 853 * CopyFrom->ImageDesc.Width);
+ − 854
+ − 855 /* finally, the extension blocks */
+ − 856 if (sp->ExtensionBlocks)
+ − 857 {
+ − 858 sp->ExtensionBlocks
+ − 859 = (ExtensionBlock*)malloc(sizeof(ExtensionBlock)
+ − 860 * CopyFrom->ExtensionBlockCount);
+ − 861 memcpy(sp->ExtensionBlocks,
+ − 862 CopyFrom->ExtensionBlocks,
+ − 863 sizeof(ExtensionBlock)
+ − 864 * CopyFrom->ExtensionBlockCount);
+ − 865
+ − 866 /*
+ − 867 * For the moment, the actual blocks can take their
+ − 868 * chances with free(). We'll fix this later.
+ − 869 */
+ − 870 }
+ − 871 }
+ − 872
+ − 873 return(sp);
+ − 874 }
+ − 875 }
+ − 876
+ − 877 void FreeSavedImages(GifFileType *GifFile)
+ − 878 {
+ − 879 SavedImage *sp;
+ − 880
+ − 881 for (sp = GifFile->SavedImages;
+ − 882 sp < GifFile->SavedImages + GifFile->ImageCount;
+ − 883 sp++)
+ − 884 {
+ − 885 if (sp->ImageDesc.ColorMap)
+ − 886 FreeMapObject(sp->ImageDesc.ColorMap);
+ − 887
+ − 888 if (sp->RasterBits)
+ − 889 free((char *)sp->RasterBits);
+ − 890
+ − 891 if (sp->ExtensionBlocks)
+ − 892 FreeExtension(sp);
+ − 893 }
+ − 894 free((char *) GifFile->SavedImages);
+ − 895 }
+ − 896
+ − 897 /******************************************************************************
+ − 898 * Miscellaneous utility functions *
+ − 899 ******************************************************************************/
+ − 900
+ − 901 static int BitSize(int n)
+ − 902 /* return smallest bitfield size n will fit in */
+ − 903 {
+ − 904 register int i;
+ − 905
+ − 906 for (i = 1; i <= 8; i++)
+ − 907 if ((1 << i) >= n)
+ − 908 break;
+ − 909 return(i);
+ − 910 }
+ − 911
+ − 912 /******************************************************************************
+ − 913 * Color map object functions *
+ − 914 ******************************************************************************/
+ − 915
+ − 916 ColorMapObject *MakeMapObject(int ColorCount, GifColorType *ColorMap)
+ − 917 /*
+ − 918 * Allocate a color map of given size; initialize with contents of
+ − 919 * ColorMap if that pointer is non-NULL.
+ − 920 */
+ − 921 {
+ − 922 ColorMapObject *Object;
+ − 923
+ − 924 if (ColorCount != (1 << BitSize(ColorCount)))
+ − 925 return((ColorMapObject *)NULL);
+ − 926
+ − 927 Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
+ − 928 if (Object == (ColorMapObject *)NULL)
+ − 929 return((ColorMapObject *)NULL);
+ − 930
+ − 931 Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
+ − 932 if (Object->Colors == (GifColorType *)NULL)
+ − 933 return((ColorMapObject *)NULL);
+ − 934
+ − 935 Object->ColorCount = ColorCount;
+ − 936 Object->BitsPerPixel = BitSize(ColorCount);
+ − 937
+ − 938 if (ColorMap)
+ − 939 memcpy((char *)Object->Colors,
+ − 940 (char *)ColorMap, ColorCount * sizeof(GifColorType));
+ − 941
+ − 942 return(Object);
+ − 943 }
+ − 944
+ − 945 void FreeMapObject(ColorMapObject *Object)
+ − 946 /*
+ − 947 * Free a color map object
+ − 948 */
+ − 949 {
+ − 950 free(Object->Colors);
+ − 951 free(Object);
+ − 952 }