]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-wbmp.c
Fix compiler warnings
[~andy/gtk] / gdk-pixbuf / io-wbmp.c
1 /* GdkPixbuf library - Wireless Bitmap image loader
2  *
3  * Copyright (C) 2000 Red Hat, Inc.
4  *
5  * Authors: Elliot Lee <sopwith@redhat.com
6  *
7  * Based on io-bmp.c
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26
27 Known bugs:
28         * Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
29 */
30
31 #include <config.h>
32 #include <stdio.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <string.h>
37 #include "gdk-pixbuf-private.h"
38 #include "gdk-pixbuf-io.h"
39
40 \f
41
42 /* Progressive loading */
43
44 struct wbmp_progressive_state {
45   ModulePreparedNotifyFunc prepared_func;
46   ModuleUpdatedNotifyFunc updated_func;
47   gpointer user_data;
48
49   gboolean need_type : 1;
50   gboolean need_header : 1;
51   gboolean need_width : 1;
52   gboolean need_height : 1;
53   gboolean needmore : 1;
54   gboolean call_progressive_updates : 1;
55
56   guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
57   guint last_len;
58
59   int type;
60   int width, height, curx, cury;
61
62   GdkPixbuf *pixbuf;    /* Our "target" */
63 };
64
65 gpointer
66 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
67                                   ModuleUpdatedNotifyFunc updated_func,
68                                   ModuleFrameDoneNotifyFunc frame_done_func,
69                                   ModuleAnimationDoneNotifyFunc
70                                   anim_done_func, gpointer user_data);
71
72 void gdk_pixbuf__wbmp_image_stop_load(gpointer data);
73 gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf,
74                                                guint size);
75
76
77 /* Shared library entry point --> This should be removed when
78    generic_image_load enters gdk-pixbuf-io. */
79 GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f)
80 {
81         size_t length;
82         char membuf[4096];
83         struct wbmp_progressive_state *State;
84
85         GdkPixbuf *pb;
86
87         State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL);
88
89         while (feof(f) == 0) {
90                 length = fread(membuf, 1, 4096, f);
91                 if (length > 0)
92                   gdk_pixbuf__wbmp_image_load_increment(State,
93                                                         membuf,
94                                                         length);
95
96         }
97         if (State->pixbuf != NULL)
98                 gdk_pixbuf_ref(State->pixbuf);
99
100         pb = State->pixbuf;
101
102         gdk_pixbuf__wbmp_image_stop_load(State);
103         return pb;
104 }
105
106 /* 
107  * func - called when we have pixmap created (but no image data)
108  * user_data - passed as arg 1 to func
109  * return context (opaque to user)
110  */
111
112 gpointer
113 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
114                                  ModuleUpdatedNotifyFunc updated_func,
115                                  ModuleFrameDoneNotifyFunc frame_done_func,
116                                  ModuleAnimationDoneNotifyFunc
117                                  anim_done_func, gpointer user_data)
118 {
119         struct wbmp_progressive_state *context;
120
121         context = g_new0(struct wbmp_progressive_state, 1);
122         context->prepared_func = prepared_func;
123         context->updated_func = updated_func;
124         context->user_data = user_data;
125
126         context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
127         context->call_progressive_updates = TRUE;
128         context->pixbuf = NULL;
129
130         return (gpointer) context;
131 }
132
133 /*
134  * context - returned from image_begin_load
135  *
136  * free context, unref gdk_pixbuf
137  */
138 void gdk_pixbuf__wbmp_image_stop_load(gpointer data)
139 {
140         struct wbmp_progressive_state *context =
141             (struct wbmp_progressive_state *) data;
142
143         g_return_if_fail(context != NULL);
144         if (context->pixbuf)
145           gdk_pixbuf_unref(context->pixbuf);
146
147         g_free(context);
148 }
149
150 static gboolean
151 getin(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
152 {
153   int last_num, buf_num;
154
155   if((context->last_len + *buf_size) < datum_size)
156     return FALSE;
157
158   /* We know we can pull it out of there */
159   last_num = MIN(datum_size, context->last_len);
160   buf_num = MIN(datum_size-last_num, *buf_size);
161   memcpy(ptr, context->last_buf, last_num);
162   memcpy(ptr+last_num, *buf, buf_num);
163          
164   context->last_len -= last_num;
165   if(context->last_len)
166     memmove(context->last_buf, context->last_buf+last_num, context->last_len);
167   *buf_size -= buf_num;
168   *buf += buf_num;
169
170   return TRUE;
171 }
172
173 static gboolean
174 save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
175 {
176   if(buf_size > (sizeof(context->last_buf) - context->last_len))
177     return FALSE;
178
179   memcpy(context->last_buf+context->last_len, buf, buf_size);
180   context->last_len += buf_size;
181
182   return TRUE;
183 }
184
185 static gboolean
186 get_mbi(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, int *val)
187 {
188   guchar intbuf[16];
189   int i, n;
190   gboolean rv;
191
192   *val = 0;
193   n = i = 0;
194   do {
195     rv = getin(context, buf, buf_size, intbuf+n, 1);
196     if(!rv)
197       goto out;
198     *val <<= 7;
199     *val |= intbuf[n] & 0x7F;
200     n++;
201   } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
202
203  out:
204   if(!rv || (intbuf[n-1] & 0x80))
205     {
206       rv = save_rest(context, intbuf, n);
207
208       if(!rv)
209         g_error("Couldn't save_rest of intbuf");
210       return FALSE;
211     }
212
213   return TRUE;
214 }
215
216 /*
217  * context - from image_begin_load
218  * buf - new image data
219  * size - length of new image data
220  *
221  * append image data onto inrecrementally built output image
222  */
223 gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf,
224                                               guint size)
225 {
226         struct wbmp_progressive_state *context =
227             (struct wbmp_progressive_state *) data;
228         gboolean bv = FALSE;
229
230         do
231           {
232             if(context->need_type)
233               {
234                 guchar val;
235
236                 bv = getin(context, &buf, &size, &val, 1);
237                 if(bv)
238                   {
239                     context->type = val;
240                     context->need_type = FALSE;
241                   }
242               }
243             else if(context->need_header)
244               {
245                 guchar val;
246
247                 bv = getin(context, &buf, &size, &val, 1);
248                 if(bv)
249                   {
250                     /* We skip over the extended header - val is unused */
251                     if(!(val & 0x80))
252                       context->need_header = FALSE;
253                   }
254               }
255             else if(context->need_width)
256               {
257                 bv = get_mbi(context, &buf, &size, &context->width);
258                 if(bv)
259                   context->need_width = FALSE;
260               }
261             else if(context->need_height)
262               {
263                 bv = get_mbi(context, &buf, &size, &context->height);
264                 if(bv)
265                   {
266                     context->need_height = FALSE;
267                     context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
268                     g_assert(context->pixbuf);
269
270                     if(context->prepared_func)
271                       context->prepared_func(context->pixbuf, context->user_data);
272                   }
273               }
274             else if(context->needmore)
275               {
276                 int first_row;
277                 first_row = context->cury;
278                 for( ; context->cury < context->height; context->cury++, context->curx = 0)
279                   {
280                     for( ; context->curx < context->width; context->curx += 8)
281                       {
282                         guchar byte;
283                         guchar *ptr;
284                         int xoff;
285                         bv = getin(context, &buf, &size, &byte, 1);
286                         if(!bv)
287                           goto out;
288
289                         ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
290                         for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
291                           {
292                             guchar pixval;
293
294                             if(byte & (1<<xoff))
295                               pixval = 0xFF;
296                             else
297                               pixval = 0x0;
298
299                             ptr[0] = ptr[1] = ptr[2] = pixval;
300                           }
301                       }
302                   }
303                 context->needmore = FALSE;
304
305               out:
306                 context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
307                                       context->user_data);
308               }
309             else
310               bv = FALSE; /* Nothing left to do, stop feeding me data! */
311
312           } while(bv);
313
314         if(size)
315           return save_rest(context, buf, size);
316         else
317           return context->needmore;
318 }