]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-wbmp.c
Add built marshaller files to support GdkPixbufLoader signals
[~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 static 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                                   GError **error);
72
73 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
74 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
75                                                       const guchar * buf,
76                                                       guint size,
77                                                       GError **error);
78
79
80 /* Shared library entry point --> This should be removed when
81    generic_image_load enters gdk-pixbuf-io. */
82 static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
83 {
84         size_t length;
85         char membuf[4096];
86         struct wbmp_progressive_state *State;
87
88         GdkPixbuf *pb;
89
90         State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
91                                                   error);
92
93         if (State == NULL)
94           return NULL;
95         
96         while (feof(f) == 0) {
97                 length = fread(membuf, 1, 4096, f);
98                 if (length > 0)
99                   gdk_pixbuf__wbmp_image_load_increment(State,
100                                                         membuf,
101                                                         length,
102                                                         error);
103
104         }
105         if (State->pixbuf != NULL)
106                 gdk_pixbuf_ref(State->pixbuf);
107
108         pb = State->pixbuf;
109
110         gdk_pixbuf__wbmp_image_stop_load(State, NULL);
111         return pb;
112 }
113
114 /* 
115  * func - called when we have pixmap created (but no image data)
116  * user_data - passed as arg 1 to func
117  * return context (opaque to user)
118  */
119
120 static gpointer
121 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
122                                   ModuleUpdatedNotifyFunc updated_func,
123                                   ModuleFrameDoneNotifyFunc frame_done_func,
124                                   ModuleAnimationDoneNotifyFunc
125                                   anim_done_func, gpointer user_data,
126                                   GError **error)
127 {
128         struct wbmp_progressive_state *context;
129
130         context = g_new0(struct wbmp_progressive_state, 1);
131         context->prepared_func = prepared_func;
132         context->updated_func = updated_func;
133         context->user_data = user_data;
134
135         context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
136         context->call_progressive_updates = TRUE;
137         context->pixbuf = NULL;
138
139         return (gpointer) context;
140 }
141
142 /*
143  * context - returned from image_begin_load
144  *
145  * free context, unref gdk_pixbuf
146  */
147 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
148                                                  GError **error)
149 {
150         struct wbmp_progressive_state *context =
151             (struct wbmp_progressive_state *) data;
152
153         /* FIXME this thing needs to report errors if
154          * we have unused image data
155          */
156         
157         g_return_val_if_fail(context != NULL, TRUE);
158         if (context->pixbuf)
159           gdk_pixbuf_unref(context->pixbuf);
160
161         g_free(context);
162
163         return TRUE;
164 }
165
166 static gboolean
167 getin(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
168 {
169   int last_num, buf_num;
170
171   if((context->last_len + *buf_size) < datum_size)
172     return FALSE;
173
174   /* We know we can pull it out of there */
175   last_num = MIN(datum_size, context->last_len);
176   buf_num = MIN(datum_size-last_num, *buf_size);
177   memcpy(ptr, context->last_buf, last_num);
178   memcpy(ptr+last_num, *buf, buf_num);
179          
180   context->last_len -= last_num;
181   if(context->last_len)
182     memmove(context->last_buf, context->last_buf+last_num, context->last_len);
183   *buf_size -= buf_num;
184   *buf += buf_num;
185
186   return TRUE;
187 }
188
189 static gboolean
190 save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
191 {
192   if(buf_size > (sizeof(context->last_buf) - context->last_len))
193     return FALSE;
194
195   memcpy(context->last_buf+context->last_len, buf, buf_size);
196   context->last_len += buf_size;
197
198   return TRUE;
199 }
200
201 static gboolean
202 get_mbi(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, int *val)
203 {
204   guchar intbuf[16];
205   int i, n;
206   gboolean rv;
207
208   *val = 0;
209   n = i = 0;
210   do {
211     rv = getin(context, buf, buf_size, intbuf+n, 1);
212     if(!rv)
213       goto out;
214     *val <<= 7;
215     *val |= intbuf[n] & 0x7F;
216     n++;
217   } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
218
219  out:
220   if(!rv || (intbuf[n-1] & 0x80))
221     {
222       rv = save_rest(context, intbuf, n);
223
224       if(!rv)
225         g_error("Couldn't save_rest of intbuf");
226       return FALSE;
227     }
228
229   return TRUE;
230 }
231
232 /*
233  * context - from image_begin_load
234  * buf - new image data
235  * size - length of new image data
236  *
237  * append image data onto inrecrementally built output image
238  */
239 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
240                                                       const guchar * buf,
241                                                       guint size, GError **error)
242 {
243         struct wbmp_progressive_state *context =
244             (struct wbmp_progressive_state *) data;
245         gboolean bv = FALSE;
246
247         do
248           {
249             if(context->need_type)
250               {
251                 guchar val;
252
253                 bv = getin(context, &buf, &size, &val, 1);
254                 if(bv)
255                   {
256                     context->type = val;
257                     context->need_type = FALSE;
258                   }
259               }
260             else if(context->need_header)
261               {
262                 guchar val;
263
264                 bv = getin(context, &buf, &size, &val, 1);
265                 if(bv)
266                   {
267                     /* We skip over the extended header - val is unused */
268                     if(!(val & 0x80))
269                       context->need_header = FALSE;
270                   }
271               }
272             else if(context->need_width)
273               {
274                 bv = get_mbi(context, &buf, &size, &context->width);
275                 if(bv)
276                   context->need_width = FALSE;
277               }
278             else if(context->need_height)
279               {
280                 bv = get_mbi(context, &buf, &size, &context->height);
281                 if(bv)
282                   {
283                     context->need_height = FALSE;
284                     context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
285                     g_assert(context->pixbuf);
286
287                     if(context->prepared_func)
288                       context->prepared_func(context->pixbuf, context->user_data);
289                   }
290               }
291             else if(context->needmore)
292               {
293                 int first_row;
294                 first_row = context->cury;
295                 for( ; context->cury < context->height; context->cury++, context->curx = 0)
296                   {
297                     for( ; context->curx < context->width; context->curx += 8)
298                       {
299                         guchar byte;
300                         guchar *ptr;
301                         int xoff;
302                         bv = getin(context, &buf, &size, &byte, 1);
303                         if(!bv)
304                           goto out;
305
306                         ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
307                         for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
308                           {
309                             guchar pixval;
310
311                             if(byte & (1<<xoff))
312                               pixval = 0xFF;
313                             else
314                               pixval = 0x0;
315
316                             ptr[0] = ptr[1] = ptr[2] = pixval;
317                           }
318                       }
319                   }
320                 context->needmore = FALSE;
321
322               out:
323                 context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
324                                       context->user_data);
325               }
326             else
327               bv = FALSE; /* Nothing left to do, stop feeding me data! */
328
329           } while(bv);
330
331         if(size)
332           return save_rest(context, buf, size);
333         else
334           return context->needmore;
335 }
336
337 void
338 gdk_pixbuf__wbmp_fill_vtable (GdkPixbufModule *module)
339 {
340   module->load = gdk_pixbuf__wbmp_image_load;
341   module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
342   module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
343   module->load_increment = gdk_pixbuf__wbmp_image_load_increment;
344 }