Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

gifread.c

Go to the documentation of this file.
00001 /* gifread.c - Functions to read GIFs.
00002    Copyright (C) 1997-9 Eddie Kohler, eddietwo@lcs.mit.edu
00003    This file is part of the GIF library.
00004 
00005    The GIF library is free software*. It is distributed under the GNU General
00006    Public License, version 2 or later; you can copy, distribute, or alter it
00007    at will, as long as this notice is kept intact and this source code is made
00008    available. There is no warranty, express or implied.
00009 
00010    *The LZW compression method used by GIFs is patented. Unisys, the patent
00011    holder, allows the compression algorithm to be used without a license in
00012    software distributed at no cost to the user. */
00013 
00014 #ifdef HAVE_CONFIG_H
00015 # include "config.h"
00016 #elif !defined(__cplusplus)
00017 /* Assume we don't have inline by default */
00018 # define inline
00019 #endif
00020 #include "gif.h"
00021 #include <stdarg.h>
00022 #include <assert.h>
00023 #include <string.h>
00024 #ifdef __cplusplus
00025 extern "C" {
00026 #endif
00027 
00028 typedef struct {
00029   
00030   Gif_Stream *stream;
00031   
00032   Gif_Code *prefix;
00033   byte *suffix;
00034   u_int16_t *length;
00035   
00036   u_int16_t width;
00037   u_int16_t height;
00038   
00039   byte *image;
00040   byte *maximage;
00041   
00042   unsigned decodepos;
00043 
00044   Gif_ReadErrorHandler handler;
00045   void *handler_thunk;
00046   
00047 } Gif_Context;
00048 
00049 
00050 typedef struct Gif_Reader {
00051   
00052   FILE *f;
00053   const byte *v;
00054   u_int32_t w;
00055   u_int32_t length;
00056   int is_record;
00057   int is_eoi;
00058   byte (*byte_getter)(struct Gif_Reader *);
00059   void (*block_getter)(byte *, u_int32_t, struct Gif_Reader *);
00060   u_int32_t (*offseter)(struct Gif_Reader *);
00061   int (*eofer)(struct Gif_Reader *);
00062   
00063 } Gif_Reader;
00064 
00065 
00066 #define gifgetc(grr)    ((char)(*grr->byte_getter)(grr))
00067 #define gifgetbyte(grr) ((*grr->byte_getter)(grr))
00068 #define gifgetblock(ptr, size, grr) ((*grr->block_getter)(ptr, size, grr))
00069 #define gifgetoffset(grr) ((*grr->offseter)(grr))
00070 #define gifeof(grr)     ((*grr->eofer)(grr))
00071 
00072 static inline u_int16_t
00073 gifgetunsigned(Gif_Reader *grr)
00074 {
00075   byte one = gifgetbyte(grr);
00076   byte two = gifgetbyte(grr);
00077   return one | (two << 8);
00078 }
00079 
00080 
00081 static byte
00082 file_byte_getter(Gif_Reader *grr)
00083 {
00084   int i = getc(grr->f);
00085   return i == EOF ? 0 : (byte)i;
00086 }
00087 
00088 static void
00089 file_block_getter(byte *p, u_int32_t s, Gif_Reader *grr)
00090 {
00091   fread(p, 1, s, grr->f);
00092 }
00093 
00094 static u_int32_t
00095 file_offseter(Gif_Reader *grr)
00096 {
00097   return ftell(grr->f);
00098 }
00099 
00100 static int
00101 file_eofer(Gif_Reader *grr)
00102 {
00103   return feof(grr->f);
00104 }
00105 
00106 
00107 static byte
00108 record_byte_getter(Gif_Reader *grr)
00109 {
00110   return grr->w ? (grr->w--, *grr->v++) : 0;
00111 }
00112 
00113 static void
00114 record_block_getter(byte *p, u_int32_t s, Gif_Reader *grr)
00115 {
00116   if (s > grr->w) s = grr->w;
00117   memcpy(p, grr->v, s);
00118   grr->w -= s, grr->v += s;
00119 }
00120 
00121 static u_int32_t
00122 record_offseter(Gif_Reader *grr)
00123 {
00124   return grr->length - grr->w;
00125 }
00126 
00127 static int
00128 record_eofer(Gif_Reader *grr)
00129 {
00130   return grr->w == 0;
00131 }
00132 
00133 
00134 static void
00135 make_data_reader(Gif_Reader *grr, const byte *data, u_int32_t length)
00136 {
00137   grr->v = data;
00138   grr->length = length;
00139   grr->w = length;
00140   grr->is_record = 1;
00141   grr->byte_getter = record_byte_getter;
00142   grr->block_getter = record_block_getter;
00143   grr->offseter = record_offseter;
00144   grr->eofer = record_eofer;
00145 }
00146 
00147 
00148 static void
00149 gif_read_error(Gif_Context *gfc, const char *error)
00150 {
00151   gfc->stream->errors++;
00152   if (gfc->handler)
00153     gfc->handler(error, gfc->stream->nimages, gfc->handler_thunk);
00154 }
00155 
00156 
00157 static byte
00158 one_code(Gif_Context *gfc, Gif_Code code)
00159 {
00160   byte *suffixes = gfc->suffix;
00161   Gif_Code *prefixes = gfc->prefix;
00162   byte *ptr;
00163   int lastsuffix;
00164   u_int16_t codelength = gfc->length[code];
00165 
00166   gfc->decodepos += codelength;
00167   ptr = gfc->image + gfc->decodepos;
00168   if (ptr > gfc->maximage || !codelength) {
00169     gif_read_error(gfc, (!codelength ? "bad code" : "too much image data"));
00170     /* 5/26/98 It's not good enough simply to count an error, because in the
00171        read_image_data function, if code == next_code, we will store a byte in
00172        gfc->image[gfc->decodepos-1]. Thus, fix decodepos so it's w/in the
00173        image. */
00174     gfc->decodepos = gfc->maximage - gfc->image;
00175     return 0;
00176   }
00177   
00178   /* codelength will always be greater than 0. */
00179   do {
00180     lastsuffix = suffixes[code];
00181     *--ptr = lastsuffix;
00182     code = prefixes[code];
00183   } while (--codelength > 0);
00184   
00185   /* return the first pixel in the code, which, since we walked backwards
00186      through the code, was the last suffix we processed. */
00187   return lastsuffix;
00188 }
00189 
00190 static int
00191 read_image_block(Gif_Reader *grr, byte *buffer, int *bit_pos_store,
00192                  int *bit_len_store, int bits_needed)
00193 {
00194   int bit_position = *bit_pos_store;
00195   int bit_length = *bit_len_store;
00196   byte block_len;
00197   
00198   while (bit_position + bits_needed > bit_length) {
00199     /* Read in the next data block. */
00200     if (bit_position >= 8) {
00201       /* Need to shift down the upper, unused part of `buffer' */
00202       int i = bit_position / 8;
00203       buffer[0] = buffer[i];
00204       buffer[1] = buffer[i+1];
00205       bit_position -= i * 8;
00206       bit_length -= i * 8;
00207     }
00208     block_len = gifgetbyte(grr);
00209     GIF_DEBUG(("\nimage_block(%d)", block_len));
00210     if (block_len == 0) return 0;
00211     gifgetblock(buffer + bit_length / 8, block_len, grr);
00212     bit_length += block_len * 8;
00213   }
00214   
00215   *bit_pos_store = bit_position;
00216   *bit_len_store = bit_length;
00217   return 1;
00218 }
00219 
00220 
00221 static void
00222 read_image_data(Gif_Context *gfc, Gif_Reader *grr)
00223 {
00224   /* we need a bit more than GIF_MAX_BLOCK in case a single code is split
00225      across blocks */
00226   byte buffer[GIF_MAX_BLOCK + 5];
00227   int i;
00228   u_int32_t accum;
00229   
00230   int bit_position;
00231   int bit_length;
00232   
00233   Gif_Code code;
00234   Gif_Code old_code;
00235   Gif_Code clear_code;
00236   Gif_Code eoi_code;
00237   Gif_Code next_code;
00238 #define CUR_BUMP_CODE (1 << bits_needed)
00239 #define CUR_CODE_MASK ((1 << bits_needed) - 1)
00240   
00241   int min_code_size;
00242   int bits_needed;
00243   
00244   gfc->decodepos = 0;
00245   
00246   min_code_size = gifgetbyte(grr);
00247   GIF_DEBUG(("\n\nmin_code_size(%d)", min_code_size));
00248   if (min_code_size >= GIF_MAX_CODE_BITS) {
00249     gif_read_error(gfc, "min_code_size too big");
00250     min_code_size = GIF_MAX_CODE_BITS - 1;
00251   } else if (min_code_size < 2) {
00252     gif_read_error(gfc, "min_code_size too small");
00253     min_code_size = 2;
00254   }
00255   clear_code = 1 << min_code_size;
00256   for (code = 0; code < clear_code; code++) {
00257     gfc->prefix[code] = 49428;
00258     gfc->suffix[code] = (byte)code;
00259     gfc->length[code] = 1;
00260   }
00261   eoi_code = clear_code + 1;
00262   
00263   next_code = eoi_code;
00264   bits_needed = min_code_size + 1;
00265   
00266   code = clear_code;
00267   
00268   bit_length = bit_position = 0;
00269   /* Thus the `Read in the next data block.' code below will be invoked on the
00270      first time through: exactly right! */
00271   
00272   while (1) {
00273     
00274     old_code = code;
00275     
00276     /* GET A CODE INTO THE `code' VARIABLE.
00277      * 
00278      * 9.Dec.1998 - Rather than maintain a byte pointer and a bit offset into
00279      * the current byte (and the processing associated with that), we maintain
00280      * one number: the offset, in bits, from the beginning of `buffer'. This
00281      * much cleaner choice was inspired by Patrick J. Naughton
00282      * <naughton@wind.sun.com>'s GIF-reading code, which does the same thing.
00283      * His code distributed as part of XV in xvgif.c. */
00284     
00285     if (bit_position + bits_needed > bit_length)
00286       /* Read in the next data block. */
00287       if (!read_image_block(grr, buffer, &bit_position, &bit_length,
00288                             bits_needed))
00289         goto zero_length_block;
00290     
00291     i = bit_position / 8;
00292     accum = buffer[i] + (buffer[i+1] << 8);
00293     if (bits_needed >= 8)
00294       accum |= (buffer[i+2]) << 16;
00295     code = (Gif_Code)((accum >> (bit_position % 8)) & CUR_CODE_MASK);
00296     bit_position += bits_needed;
00297     
00298     GIF_DEBUG(("%d", code));
00299     
00300     /* CHECK FOR SPECIAL OR BAD CODES: clear_code, eoi_code, or a code that is
00301      * too large. */
00302     if (code == clear_code) {
00303       bits_needed = min_code_size + 1;
00304       next_code = eoi_code;
00305       continue;
00306       
00307     } else if (code == eoi_code)
00308       break;
00309     
00310     else if (code > next_code && next_code) {
00311       /* code > next_code: a (hopefully recoverable) error.
00312          
00313          Bug fix, 5/27: Do this even if old_code == clear_code, and set code
00314          to 0 to prevent errors later. (If we didn't zero code, we'd later set
00315          old_code = code; then we had old_code >= next_code; so the prefixes
00316          array got all screwed up!) */
00317       gif_read_error(gfc, "unexpected code");
00318       code = 0;
00319     }
00320     
00321     /* PROCESS THE CURRENT CODE and define the next code. If no meaningful
00322      * next code should be defined, then we have set next_code to either
00323      * `eoi_code' or `clear_code' -- so we'll store useless prefix/suffix data
00324      * in a useless place. */
00325     
00326     /* *First,* set up the prefix and length for the next code
00327        (in case code == next_code). */
00328     gfc->prefix[next_code] = old_code;
00329     gfc->length[next_code] = gfc->length[old_code] + 1;
00330     
00331     /* Use one_code to process code. It's nice that it returns the first
00332        pixel in code: that's what we need. */
00333     gfc->suffix[next_code] = one_code(gfc, code);
00334     
00335     /* Special processing if code == next_code: we didn't know code's final
00336        suffix when we called one_code, but we do now. */
00337     if (code == next_code)
00338       gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code];
00339     
00340     /* Increment next_code except for the `clear_code' special case (that's
00341        when we're reading at the end of a GIF) */
00342     if (next_code != clear_code) {
00343       next_code++;
00344       if (next_code == CUR_BUMP_CODE) {
00345         if (bits_needed < GIF_MAX_CODE_BITS)
00346           bits_needed++;
00347         else
00348           next_code = clear_code;
00349       }
00350     }
00351     
00352   }
00353   
00354   /* read blocks until zero-length reached. */
00355   i = gifgetbyte(grr);
00356   GIF_DEBUG(("\nafter_image(%d)\n", i));
00357   while (i > 0) {
00358     gifgetblock(buffer, i, grr);
00359     i = gifgetbyte(grr);
00360     GIF_DEBUG(("\nafter_image(%d)\n", i));
00361   }
00362   
00363   /* zero-length block reached. */
00364  zero_length_block:
00365   
00366   if (gfc->image + gfc->decodepos < gfc->maximage)
00367     gif_read_error(gfc, "not enough image data for image size");
00368   else if (gfc->image + gfc->decodepos > gfc->maximage)
00369     gif_read_error(gfc, "too much image data for image size");
00370 }
00371 
00372 
00373 static Gif_Colormap *
00374 read_color_table(int size, Gif_Reader *grr)
00375 {
00376   Gif_Colormap *gfcm = Gif_NewFullColormap(size, size);
00377   Gif_Color *c;
00378   if (!gfcm) return 0;
00379   
00380   GIF_DEBUG(("colormap(%d)", size));
00381   for (c = gfcm->col; size; size--, c++) {
00382     c->red = gifgetbyte(grr);
00383     c->green = gifgetbyte(grr);
00384     c->blue = gifgetbyte(grr);
00385     c->haspixel = 0;
00386   }
00387   
00388   return gfcm;
00389 }
00390 
00391 
00392 static int
00393 read_logical_screen_descriptor(Gif_Stream *gfs, Gif_Reader *grr)
00394      /* returns 0 on memory error */
00395 {
00396   byte packed;
00397   
00398   /* we don't care about logical screen width or height */
00399   gfs->screen_width = gifgetunsigned(grr);
00400   gfs->screen_height = gifgetunsigned(grr);
00401   
00402   packed = gifgetbyte(grr);
00403   gfs->background = gifgetbyte(grr);
00404   
00405   /* don't care about pixel aspect ratio */
00406   gifgetbyte(grr);
00407   
00408   if (packed & 0x80) { /* have a global color table */
00409     int ncol = 1 << ((packed & 0x07) + 1);
00410     gfs->global = read_color_table(ncol, grr);
00411     if (!gfs->global) return 0;
00412     gfs->global->refcount = 1;
00413   }
00414   
00415   return 1;
00416 }
00417 
00418 
00419 static int
00420 read_compressed_image(Gif_Image *gfi, Gif_Reader *grr, int read_flags)
00421 {
00422   if (grr->is_record) {
00423     const byte *first = grr->v;
00424     u_int32_t pos;
00425     
00426     /* scan over image */
00427     pos = 1;                    /* skip min code size */
00428     while (pos < grr->w) {
00429       int amt = grr->v[pos];
00430       pos += amt + 1;
00431       if (amt == 0) break;
00432     }
00433     if (pos > grr->w) pos = grr->w;
00434     
00435     gfi->compressed_len = pos;
00436     if (read_flags & GIF_READ_CONST_RECORD) {
00437       gfi->compressed = (byte *)first;
00438       gfi->free_compressed = 0;
00439     } else {
00440       gfi->compressed = Gif_NewArray(byte, gfi->compressed_len);
00441       gfi->free_compressed = Gif_DeleteArrayFunc;
00442       if (!gfi->compressed) return 0;
00443       memcpy(gfi->compressed, first, gfi->compressed_len);
00444     }
00445     
00446     /* move reader over that image */
00447     grr->v += pos;
00448     grr->w -= pos;
00449     
00450   } else {
00451     /* non-record; have to read it block by block. */
00452     u_int32_t comp_cap = 1024;
00453     u_int32_t comp_len;
00454     byte *comp = Gif_NewArray(byte, comp_cap);
00455     int i;
00456     if (!comp) return 0;
00457     
00458     /* min code size */
00459     i = gifgetbyte(grr);
00460     comp[0] = i;
00461     comp_len = 1;
00462     
00463     i = gifgetbyte(grr);
00464     while (i > 0) {
00465       /* add 2 before check so we don't have to check after loop when appending
00466          0 block */
00467       if (comp_len + i + 2 > comp_cap) {
00468         comp_cap *= 2;
00469         Gif_ReArray(comp, byte, comp_cap);
00470         if (!comp) return 0;
00471       }
00472       comp[comp_len] = i;
00473       gifgetblock(comp + comp_len + 1, i, grr);
00474       comp_len += i + 1;
00475       i = gifgetbyte(grr);
00476     }
00477     comp[comp_len++] = 0;
00478     
00479     gfi->compressed = comp;
00480     gfi->compressed_len = comp_len;
00481     gfi->free_compressed = Gif_DeleteArrayFunc;
00482   }
00483   
00484   return 1;
00485 }
00486 
00487 
00488 static int
00489 uncompress_image(Gif_Context *gfc, Gif_Image *gfi, Gif_Reader *grr)
00490 {
00491   if (!Gif_CreateUncompressedImage(gfi)) return 0;
00492   gfc->width = gfi->width;
00493   gfc->height = gfi->height;
00494   gfc->image = gfi->image_data;
00495   gfc->maximage = gfi->image_data + gfi->width * gfi->height;
00496   read_image_data(gfc, grr);
00497   return 1;
00498 }
00499 
00500 
00501 int
00502 Gif_FullUncompressImage(Gif_Image *gfi, Gif_ReadErrorHandler h, void *hthunk)
00503 {
00504   Gif_Context gfc;
00505   Gif_Stream fake_gfs;
00506   Gif_Reader grr;
00507   int ok = 0;
00508   
00509   /* return right away if image is already uncompressed. this might screw over
00510      people who expect re-uncompressing to restore the compressed version. */
00511   if (gfi->img)
00512     return 1;
00513   if (gfi->image_data)
00514     /* we have uncompressed data, but not an `img' array;
00515        this shouldn't happen */
00516     return 0;
00517   
00518   fake_gfs.errors = 0;
00519   gfc.stream = &fake_gfs;
00520   gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE);
00521   gfc.suffix = Gif_NewArray(byte, GIF_MAX_CODE);
00522   gfc.length = Gif_NewArray(u_int16_t, GIF_MAX_CODE);
00523   gfc.handler = h;
00524   gfc.handler_thunk = hthunk;
00525   
00526   if (gfi && gfc.prefix && gfc.suffix && gfc.length && gfi->compressed) {
00527     make_data_reader(&grr, gfi->compressed, gfi->compressed_len);
00528     ok = uncompress_image(&gfc, gfi, &grr);
00529   }
00530   
00531   Gif_DeleteArray(gfc.prefix);
00532   Gif_DeleteArray(gfc.suffix);
00533   Gif_DeleteArray(gfc.length);
00534   return ok && !fake_gfs.errors;
00535 }
00536 
00537 
00538 static int
00539 read_image(Gif_Reader *grr, Gif_Context *gfc, Gif_Image *gfi, int read_flags)
00540      /* returns 0 on memory error */
00541 {
00542   byte packed;
00543   
00544   gfi->left = gifgetunsigned(grr);
00545   gfi->top = gifgetunsigned(grr);
00546   gfi->width = gifgetunsigned(grr);
00547   gfi->height = gifgetunsigned(grr);
00548   packed = gifgetbyte(grr);
00549   GIF_DEBUG(("<%ux%u>", gfi->width, gfi->height));
00550   
00551   if (packed & 0x80) { /* have a local color table */
00552     int ncol = 1 << ((packed & 0x07) + 1);
00553     gfi->local = read_color_table(ncol, grr);
00554     if (!gfi->local) return 0;
00555     gfi->local->refcount = 1;
00556   }
00557   
00558   gfi->interlace = (packed & 0x40) != 0;
00559   
00560   /* Keep the compressed data if asked */
00561   if (read_flags & GIF_READ_COMPRESSED) {
00562     if (!read_compressed_image(gfi, grr, read_flags))
00563       return 0;
00564     if (read_flags & GIF_READ_UNCOMPRESSED) {
00565       Gif_Reader new_grr;
00566       make_data_reader(&new_grr, gfi->compressed, gfi->compressed_len);
00567       if (!uncompress_image(gfc, gfi, &new_grr))
00568         return 0;
00569     }
00570     
00571   } else if (read_flags & GIF_READ_UNCOMPRESSED) {
00572     if (!uncompress_image(gfc, gfi, grr))
00573       return 0;
00574     
00575   } else {
00576     /* skip over the image */
00577     byte buffer[GIF_MAX_BLOCK];
00578     int i = gifgetbyte(grr);
00579     while (i > 0) {
00580       gifgetblock(buffer, i, grr);
00581       i = gifgetbyte(grr);
00582     }
00583   }
00584   
00585   return 1;
00586 }
00587 
00588 
00589 static void
00590 read_graphic_control_extension(Gif_Context *gfc, Gif_Image *gfi,
00591                                Gif_Reader *grr)
00592 {
00593   byte len;
00594   byte crap[GIF_MAX_BLOCK];
00595   
00596   len = gifgetbyte(grr);
00597   
00598   if (len == 4) {
00599     byte packed = gifgetbyte(grr);
00600     gfi->disposal = (packed >> 2) & 0x07;
00601     gfi->delay = gifgetunsigned(grr);
00602     gfi->transparent = gifgetbyte(grr);
00603     if (!(packed & 0x01)) /* transparent color doesn't exist */
00604       gfi->transparent = -1;
00605     len -= 4;
00606   }
00607   
00608   if (len > 0) {
00609     gif_read_error(gfc, "odd graphic extension format");
00610     gifgetblock(crap, len, grr);
00611   }
00612   
00613   len = gifgetbyte(grr);
00614   while (len > 0) {
00615     gif_read_error(gfc, "odd graphic extension format");
00616     gifgetblock(crap, len, grr);
00617     len = gifgetbyte(grr);
00618   }
00619 }
00620 
00621 
00622 static char *last_name;
00623 
00624 
00625 static char *
00626 suck_data(char *data, int *store_len, Gif_Reader *grr)
00627 {
00628   byte len = gifgetbyte(grr);
00629   int total_len = 0;
00630   
00631   while (len > 0) {
00632     Gif_ReArray(data, char, total_len + len + 1);
00633     if (!data) return 0;
00634     gifgetblock((byte *)data, len, grr);
00635     
00636     total_len += len;
00637     data[total_len] = 0;
00638     
00639     len = gifgetbyte(grr);
00640   }
00641   
00642   if (store_len) *store_len = total_len;
00643   return data;
00644 }
00645 
00646 
00647 static int
00648 read_unknown_extension(Gif_Stream *gfs, int kind, char *app_name, int position,
00649                        Gif_Reader *grr)
00650 {
00651   byte block_len = gifgetbyte(grr);
00652   byte *data = 0;
00653   byte data_len = 0;
00654   Gif_Extension *gfex = 0;
00655 
00656   while (block_len > 0) {
00657     if (data) Gif_ReArray(data, byte, data_len + block_len + 1);
00658     else data = Gif_NewArray(byte, block_len + 1);
00659     if (!data) goto done;
00660     gifgetblock(data + data_len, block_len, grr);
00661     data_len += block_len;
00662     block_len = gifgetbyte(grr);
00663   }
00664 
00665   if (data)
00666     gfex = Gif_NewExtension(kind, app_name);
00667   if (gfex) {
00668     gfex->data = data;
00669     gfex->length = data_len;
00670     data[data_len] = 0;
00671     Gif_AddExtension(gfs, gfex, position);
00672   }
00673   
00674  done:
00675   if (!gfex) Gif_DeleteArray(data);
00676   while (block_len > 0) {
00677     byte buffer[GIF_MAX_BLOCK];
00678     gifgetblock(buffer, block_len, grr);
00679     block_len = gifgetbyte(grr);
00680   }
00681   return gfex != 0;
00682 }
00683 
00684 
00685 static int
00686 read_application_extension(Gif_Context *gfc, Gif_Image *gfi, int position,
00687                            Gif_Reader *grr)
00688 {
00689   Gif_Stream *gfs = gfc->stream;
00690   byte buffer[GIF_MAX_BLOCK + 1];
00691   byte len = gifgetbyte(grr);
00692   gifgetblock(buffer, len, grr);
00693   
00694   /* Read the Netscape loop extension. */
00695   if (len == 11 && memcmp(buffer, "NETSCAPE2.0", 11) == 0) {
00696     
00697     len = gifgetbyte(grr);
00698     if (len == 3) {
00699       gifgetbyte(grr); /* throw away the 1 */
00700       gfs->loopcount = gifgetunsigned(grr);
00701       len = gifgetbyte(grr);
00702       if (len) gif_read_error(gfc, "bad loop extension");
00703     } else
00704       gif_read_error(gfc, "bad loop extension");
00705     
00706     while (len > 0) {
00707       gifgetblock(buffer, len, grr);
00708       len = gifgetbyte(grr);
00709     }
00710     return 1;
00711     
00712   } else {
00713     buffer[len] = 0;
00714     return read_unknown_extension(gfs, 0xFF, (char *)buffer, position, grr);
00715   }
00716 }
00717 
00718 
00719 static int
00720 read_comment_extension(Gif_Image *gfi, Gif_Reader *grr)
00721 {
00722   int len;
00723   Gif_Comment *gfcom = gfi->comment;
00724   char *m = suck_data(0, &len, grr);
00725   if (m) {
00726     if (!gfcom)
00727       gfcom = gfi->comment = Gif_NewComment();
00728     if (!gfcom || !Gif_AddCommentTake(gfcom, m, len))
00729       return 0;
00730   }
00731   return 1;
00732 }
00733 
00734 
00735 static Gif_Stream *
00736 read_gif(Gif_Reader *grr, int read_flags,
00737          Gif_ReadErrorHandler handler, void *handler_thunk)
00738 {
00739   Gif_Stream *gfs;
00740   Gif_Image *gfi;
00741   Gif_Image *new_gfi;
00742   Gif_Context gfc;
00743   int extension_position = 0;
00744   int unknown_block_type = 0;
00745   
00746   if (gifgetc(grr) != 'G' ||
00747       gifgetc(grr) != 'I' ||
00748       gifgetc(grr) != 'F')
00749     return 0;
00750   (void)gifgetc(grr);
00751   (void)gifgetc(grr);
00752   (void)gifgetc(grr);
00753   
00754   gfs = Gif_NewStream();
00755   gfi = Gif_NewImage();
00756   
00757   gfc.stream = gfs;
00758   gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE);
00759   gfc.suffix = Gif_NewArray(byte, GIF_MAX_CODE);
00760   gfc.length = Gif_NewArray(u_int16_t, GIF_MAX_CODE);
00761   gfc.handler = handler;
00762   gfc.handler_thunk = handler_thunk;
00763   
00764   if (!gfs || !gfi || !gfc.prefix || !gfc.suffix || !gfc.length)
00765     goto done;
00766   
00767   GIF_DEBUG(("\nGIF"));
00768   if (!read_logical_screen_descriptor(gfs, grr))
00769     goto done;
00770   GIF_DEBUG(("logscrdesc"));
00771   
00772   while (!gifeof(grr)) {
00773     
00774     byte block = gifgetbyte(grr);
00775     
00776     switch (block) {
00777       
00778      case ',': /* image block */
00779       GIF_DEBUG(("imageread %d", gfs->nimages));
00780       
00781       gfi->identifier = last_name;
00782       last_name = 0;
00783       if (!read_image(grr, &gfc, gfi, read_flags)
00784           || !Gif_AddImage(gfs, gfi)) {
00785         Gif_DeleteImage(gfi);
00786         goto done;
00787       }
00788       
00789       new_gfi = Gif_NewImage();
00790       if (!new_gfi) goto done;
00791       
00792       gfi = new_gfi;
00793       extension_position++;
00794       break;
00795       
00796      case ';': /* terminator */
00797       GIF_DEBUG(("term\n"));
00798       goto done;
00799       
00800      case '!': /* extension */
00801       block = gifgetbyte(grr);
00802       GIF_DEBUG(("ext(0x%02X)", block));
00803       switch (block) {
00804         
00805        case 0xF9:
00806         read_graphic_control_extension(&gfc, gfi, grr);
00807         break;
00808         
00809        case 0xCE:
00810         last_name = suck_data(last_name, 0, grr);
00811         break;
00812         
00813        case 0xFE:
00814         if (!read_comment_extension(gfi, grr)) goto done;
00815         break;
00816         
00817        case 0xFF:
00818         read_application_extension(&gfc, gfi, extension_position, grr);
00819         break;
00820         
00821        default:
00822         read_unknown_extension(gfs, block, 0, extension_position, grr);
00823         break;
00824 
00825       }
00826       break;
00827       
00828      default:
00829        if (!unknown_block_type) {
00830          char buf[256];
00831          sprintf(buf, "unknown block type %d at file offset %d", block, gifgetoffset(grr) - 1);
00832          gif_read_error(&gfc, buf);
00833          unknown_block_type = 1;
00834        }
00835        break;
00836       
00837     }
00838     
00839   }
00840   
00841  done:
00842   
00843   /* Move comments after last image into stream. */
00844   gfs->comment = gfi->comment;
00845   gfi->comment = 0;
00846   
00847   Gif_DeleteImage(gfi);
00848   Gif_DeleteArray(last_name);
00849   Gif_DeleteArray(gfc.prefix);
00850   Gif_DeleteArray(gfc.suffix);
00851   Gif_DeleteArray(gfc.length);
00852   return gfs;
00853 }
00854 
00855 
00856 Gif_Stream *
00857 Gif_FullReadFile(FILE *f, int read_flags,
00858                  Gif_ReadErrorHandler h, void *hthunk)
00859 {
00860   Gif_Reader grr;
00861   if (!f) return 0;
00862   grr.f = f;
00863   grr.is_record = 0;
00864   grr.byte_getter = file_byte_getter;
00865   grr.block_getter = file_block_getter;
00866   grr.offseter = file_offseter;
00867   grr.eofer = file_eofer;
00868   return read_gif(&grr, read_flags, h, hthunk);
00869 }
00870 
00871 Gif_Stream *
00872 Gif_FullReadRecord(const Gif_Record *gifrec, int read_flags,
00873                    Gif_ReadErrorHandler h, void *hthunk)
00874 {
00875   Gif_Reader grr;
00876   if (!gifrec) return 0;
00877   make_data_reader(&grr, gifrec->data, gifrec->length);
00878   if (read_flags & GIF_READ_CONST_RECORD)
00879     read_flags |= GIF_READ_COMPRESSED;
00880   return read_gif(&grr, read_flags, h, hthunk);
00881 }
00882 
00883 
00884 #undef Gif_ReadFile
00885 #undef Gif_ReadRecord
00886 
00887 Gif_Stream *
00888 Gif_ReadFile(FILE *f)
00889 {
00890   return Gif_FullReadFile(f, GIF_READ_UNCOMPRESSED, 0, 0);
00891 }
00892 
00893 Gif_Stream *
00894 Gif_ReadRecord(const Gif_Record *gifrec)
00895 {
00896   return Gif_FullReadRecord(gifrec, GIF_READ_UNCOMPRESSED, 0, 0);
00897 }
00898 
00899 
00900 #ifdef __cplusplus
00901 }
00902 #endif
 

Powered by Plone

This site conforms to the following standards: