00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef HAVE_CONFIG_H
00015 # include "config.h"
00016 #elif !defined(__cplusplus)
00017
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
00171
00172
00173
00174 gfc->decodepos = gfc->maximage - gfc->image;
00175 return 0;
00176 }
00177
00178
00179 do {
00180 lastsuffix = suffixes[code];
00181 *--ptr = lastsuffix;
00182 code = prefixes[code];
00183 } while (--codelength > 0);
00184
00185
00186
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
00200 if (bit_position >= 8) {
00201
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
00225
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
00270
00271
00272 while (1) {
00273
00274 old_code = code;
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 if (bit_position + bits_needed > bit_length)
00286
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
00301
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
00312
00313
00314
00315
00316
00317 gif_read_error(gfc, "unexpected code");
00318 code = 0;
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328 gfc->prefix[next_code] = old_code;
00329 gfc->length[next_code] = gfc->length[old_code] + 1;
00330
00331
00332
00333 gfc->suffix[next_code] = one_code(gfc, code);
00334
00335
00336
00337 if (code == next_code)
00338 gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code];
00339
00340
00341
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
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
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
00395 {
00396 byte packed;
00397
00398
00399 gfs->screen_width = gifgetunsigned(grr);
00400 gfs->screen_height = gifgetunsigned(grr);
00401
00402 packed = gifgetbyte(grr);
00403 gfs->background = gifgetbyte(grr);
00404
00405
00406 gifgetbyte(grr);
00407
00408 if (packed & 0x80) {
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
00427 pos = 1;
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
00447 grr->v += pos;
00448 grr->w -= pos;
00449
00450 } else {
00451
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
00459 i = gifgetbyte(grr);
00460 comp[0] = i;
00461 comp_len = 1;
00462
00463 i = gifgetbyte(grr);
00464 while (i > 0) {
00465
00466
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
00510
00511 if (gfi->img)
00512 return 1;
00513 if (gfi->image_data)
00514
00515
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
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) {
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
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
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))
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
00695 if (len == 11 && memcmp(buffer, "NETSCAPE2.0", 11) == 0) {
00696
00697 len = gifgetbyte(grr);
00698 if (len == 3) {
00699 gifgetbyte(grr);
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 ',':
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 ';':
00797 GIF_DEBUG(("term\n"));
00798 goto done;
00799
00800 case '!':
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
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