prep for 1.2rc4 release
[rrdtool.git] / src / gifsize.c
1 /****************************************************************************
2  * RRDtool 1.2rc4  Copyright by Tobi Oetiker, 1997-2005
3  ****************************************************************************
4  * gifsize.c  provides the function gifsize which determines the size of a gif
5  ****************************************************************************/
6
7 /* This is built from code originally created by:                        */
8
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 /* +-------------------------------------------------------------------+ */
18
19
20 #include <stdio.h>
21 #include <math.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25
26 #define MAXCOLORMAPSIZE     256
27
28 #define TRUE                1
29 #define FALSE               0
30
31 #define CM_RED              0
32 #define CM_GREEN            1
33 #define CM_BLUE             2
34
35
36 #define LOCALCOLORMAP       0x80
37 #define BitSet(byte, bit)   (((byte) & (bit)) == (bit))
38
39 #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
40
41 #define LM_to_uint(a,b)     (((b)<<8)|(a))
42
43
44 static struct {
45        int     transparent;
46        int     delayTime;
47        int     inputFlag;
48        int     disposal;
49 } Gif89 = { -1, -1, -1, 0 };
50
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);
54
55 int ZeroDataBlock;
56
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;
72
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';
82
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];
93
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                }
108
109                if (c == '!') {         /* Extension */
110                        if (! ReadOK(fd,&c,1)) {
111                                return 0;
112                        }
113                        DoExtension(fd, c, &Transparent);
114                        continue;
115                }
116
117                if (c != ',') {         /* Not a valid start character */
118                        continue;
119                }
120
121                ++imageCount;
122
123                if (! ReadOK(fd,buf,9)) {
124                        return 0;
125                }
126
127                (*width) = LM_to_uint(buf[4],buf[5]);
128                (*height) = LM_to_uint(buf[6],buf[7]);
129                return 1;
130        }
131 }
132
133 static int
134 ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
135 {
136        int             i;
137        unsigned char   rgb[3];
138
139
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        }
148
149
150        return FALSE;
151 }
152
153 static int
154 DoExtension(FILE *fd, int label, int *Transparent)
155 {
156        static unsigned char     buf[256];
157
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];
166
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                ;
175
176        return FALSE;
177 }
178
179 static int
180 GetDataBlock(FILE *fd, unsigned char *buf)
181 {
182        unsigned char   count;
183
184        if (! ReadOK(fd,&count,1)) {
185                return -1;
186        }
187
188        ZeroDataBlock = count == 0;
189
190        if ((count != 0) && (! ReadOK(fd, buf, count))) {
191                return -1;
192        }
193
194        return count;
195 }
196