/*---------------------------------------------------------------------------- Dumps GIF files Chris Giese http://my.execpc.com/~geezer/ This code is public domain (no copyright). You can do whatever you want with it. May 21, 2011: - Initial release ----------------------------------------------------------------------------*/ #include /* memcmp() */ #include /* printf(), fopen(), fread(), fclose() */ /***************************************************************************** *****************************************************************************/ static unsigned read_le16(void *buf_ptr) { unsigned char *buf = buf_ptr; unsigned rv; rv = buf[1]; rv <<= 8; rv |= buf[0]; return rv; } /***************************************************************************** *****************************************************************************/ static long get_len(FILE *f) { unsigned long rv = 0; int i; while(1) { i = fgetc(f); if(i == EOF) return -1L; rv++; if(i == 0) break; rv += i; fseek(f, i, SEEK_CUR); } return rv; } /***************************************************************************** If you're wondering why I don't display the image depth... In my GIF viewer, I examine the entire GIF file, looking at the global and local palettes to figure out how many unique colors there are (and hence, the color depth). The color depth values given in the screen descriptor at the start of the GIF file are garbage -- they're completely unreliable. *****************************************************************************/ static int dump_gif(FILE *f) { unsigned char buf[13]; long pos, len; int i, j; fseek(f, 0, SEEK_SET); if(fread(buf, 1, 13, f) != 13) return -1; printf( "Offset Size Description\n" "------- -------- -----------\n" " 0 13 Screen descriptor, %ux%u\n", read_le16(&buf[6]), read_le16(&buf[8])); if(buf[10] & 0x80) { /* i = buf[10] & 0x70; i >>= 4; */ i = buf[10] & 0x07; i++; i = 1 << i; printf(" 13 %8u Global palette, %u entries\n", i * 3, i); fseek(f, i * 3, SEEK_CUR); } while(1) { pos = ftell(f); i = fgetc(f); if(i == EOF) return -1; if(i == '!') { j = fgetc(f); if(j == EOF) return -1; len = get_len(f); if(len == -1L) return -1; len += 2; printf("%7lu %8lu (!)Extension block, type 0x%02X\n", pos, len, j); } else if(i == ',') { unsigned x, y, w, h; if(fread(buf, 1, 9, f) != 9) return -1; x = read_le16(&buf[0]); y = read_le16(&buf[2]); w = read_le16(&buf[4]); h = read_le16(&buf[6]); printf("%7lu 9 (,)Image descriptor, %ux%u " "at (%u,%u)\n", pos, w, h, x, y); pos = ftell(f); if(buf[8] & 0x80) { /* i = buf[8] & 0x70; i >>= 4; */ i = buf[8] & 0x07; i++; i = 1 << i; printf("%7lu %8u Local palette, %u entries\n", pos, i * 3, i); fseek(f, i * 3, SEEK_CUR); } pos = ftell(f); j = fgetc(f); if(j == EOF) /* LZW code size */ return -1; len = get_len(f); if(len == -1L) return -1; len++; printf("%7lu %8lu LZW-compressed image data\n", pos, len); } else if(i == ';') { printf("%7lu 0 (;)End of GIF file\n", pos); break; } else { printf("%7lu ? Error; unexpected byte 0x%02X\n", pos, i); break; } } return 0; } /***************************************************************************** *****************************************************************************/ int main(int arg_c, char *arg_v[]) { unsigned char buf[13]; FILE *f; int i; for(i = 1; i < arg_c; i++) { f = fopen(arg_v[i], "rb"); if(f == NULL) { printf("Error: can't open file '%s'\n", arg_v[i]); continue; } if(fread(buf, 1, 13, f) != 13) NOT: { fclose(f); printf("Error: file '%s' is not a GIF file\n", arg_v[i]); continue; } if(memcmp(buf, "GIF87a", 6) && memcmp(buf, "GIF89a", 6)) goto NOT; printf("GIF file '%s':\n", arg_v[i]); if(dump_gif(f)) printf("Error: unexpected end-of-file\n"); fclose(f); } return 0; }