1 /****************************************************************************
2 * RRDtool 1.2.1 Copyright by Tobi Oetiker, 1997-2005
3 ****************************************************************************
4 * gifsize.c provides the function gifsize which determines the size of a gif
5 ****************************************************************************/
7 /* This is built from code originally created by: */
9 /* +-------------------------------------------------------------------+ */
10 /* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
11 /* | Permission to use, copy, modify, and distribute this software | */
12 /* | and its documentation for any purpose and without fee is hereby | */
13 /* | granted, provided that the above copyright notice appear in all | */
14 /* | copies and that both that copyright notice and this permission | */
15 /* | notice appear in supporting documentation. This software is | */
16 /* | provided "as is" without express or implied warranty. | */
17 /* +-------------------------------------------------------------------+ */
20 #include <stdio.h>
21 #include <math.h>
22 #include <string.h>
23 #include <stdlib.h>
26 #define MAXCOLORMAPSIZE 256
28 #define TRUE 1
29 #define FALSE 0
31 #define CM_RED 0
32 #define CM_GREEN 1
33 #define CM_BLUE 2
36 #define LOCALCOLORMAP 0x80
37 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
39 #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
41 #define LM_to_uint(a,b) (((b)<<8)|(a))
44 static struct {
45 int transparent;
46 int delayTime;
47 int inputFlag;
48 int disposal;
49 } Gif89 = { -1, -1, -1, 0 };
51 static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
52 static int DoExtension (FILE *fd, int label, int *Transparent);
53 static int GetDataBlock (FILE *fd, unsigned char *buf);
55 int ZeroDataBlock;
57 int
58 GifSize(FILE *fd, long *width, long *height)
59 {
60 int imageNumber;
61 int BitPixel;
62 int ColorResolution;
63 int Background;
64 int AspectRatio;
65 int Transparent = (-1);
66 unsigned char buf[16];
67 unsigned char c;
68 unsigned char ColorMap[3][MAXCOLORMAPSIZE];
69 int imageCount = 0;
70 char version[4];
71 ZeroDataBlock = FALSE;
73 imageNumber = 1;
74 if (! ReadOK(fd,buf,6)) {
75 return 0;
76 }
77 if (strncmp((char *)buf,"GIF",3) != 0) {
78 return 0;
79 }
80 strncpy(version, (char *)buf + 3, 3);
81 version[3] = '\0';
83 if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
84 return 0;
85 }
86 if (! ReadOK(fd,buf,7)) {
87 return 0;
88 }
89 BitPixel = 2<<(buf[4]&0x07);
90 ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
91 Background = buf[5];
92 AspectRatio = buf[6];
94 if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
95 if (ReadColorMap(fd, BitPixel, ColorMap)) {
96 return 0;
97 }
98 }
99 for (;;) {
100 if (! ReadOK(fd,&c,1)) {
101 return 0;
102 }
103 if (c == ';') { /* GIF terminator */
104 if (imageCount < imageNumber) {
105 return 0;
106 }
107 }
109 if (c == '!') { /* Extension */
110 if (! ReadOK(fd,&c,1)) {
111 return 0;
112 }
113 DoExtension(fd, c, &Transparent);
114 continue;
115 }
117 if (c != ',') { /* Not a valid start character */
118 continue;
119 }
121 ++imageCount;
123 if (! ReadOK(fd,buf,9)) {
124 return 0;
125 }
127 (*width) = LM_to_uint(buf[4],buf[5]);
128 (*height) = LM_to_uint(buf[6],buf[7]);
129 return 1;
130 }
131 }
133 static int
134 ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
135 {
136 int i;
137 unsigned char rgb[3];
140 for (i = 0; i < number; ++i) {
141 if (! ReadOK(fd, rgb, sizeof(rgb))) {
142 return TRUE;
143 }
144 buffer[CM_RED][i] = rgb[0] ;
145 buffer[CM_GREEN][i] = rgb[1] ;
146 buffer[CM_BLUE][i] = rgb[2] ;
147 }
150 return FALSE;
151 }
153 static int
154 DoExtension(FILE *fd, int label, int *Transparent)
155 {
156 static unsigned char buf[256];
158 switch (label) {
159 case 0xf9: /* Graphic Control Extension */
160 (void) GetDataBlock(fd, (unsigned char*) buf);
161 Gif89.disposal = (buf[0] >> 2) & 0x7;
162 Gif89.inputFlag = (buf[0] >> 1) & 0x1;
163 Gif89.delayTime = LM_to_uint(buf[1],buf[2]);
164 if ((buf[0] & 0x1) != 0)
165 *Transparent = buf[3];
167 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
168 ;
169 return FALSE;
170 default:
171 break;
172 }
173 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
174 ;
176 return FALSE;
177 }
179 static int
180 GetDataBlock(FILE *fd, unsigned char *buf)
181 {
182 unsigned char count;
184 if (! ReadOK(fd,&count,1)) {
185 return -1;
186 }
188 ZeroDataBlock = count == 0;
190 if ((count != 0) && (! ReadOK(fd, buf, count))) {
191 return -1;
192 }
194 return count;
195 }