]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-wbmp.c
[quartz] Delete the typedef of GdkDevicePrivate
[~andy/gtk] / gdk-pixbuf / io-wbmp.c
1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /* GdkPixbuf library - Wireless Bitmap image loader
3  *
4  * Copyright (C) 2000 Red Hat, Inc.
5  *
6  * Authors: Elliot Lee <sopwith@redhat.com
7  *
8  * Based on io-bmp.c
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 /*
27
28 Known bugs:
29         * Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
30 */
31
32 #include "config.h"
33 #include <stdio.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #include <string.h>
38 #include "gdk-pixbuf-private.h"
39 #include "gdk-pixbuf-io.h"
40
41 \f
42
43 /* Progressive loading */
44
45 struct wbmp_progressive_state {
46   GdkPixbufModulePreparedFunc prepared_func;
47   GdkPixbufModuleUpdatedFunc updated_func;
48   gpointer user_data;
49
50   guint need_type : 1;
51   guint need_header : 1;
52   guint need_width : 1;
53   guint need_height : 1;
54   guint needmore : 1;
55   guint call_progressive_updates : 1;
56
57   guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
58   guint last_len;
59
60   int type;
61   int width, height, curx, cury;
62
63   GdkPixbuf *pixbuf;    /* Our "target" */
64 };
65
66 static gpointer
67 gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func, 
68                                   GdkPixbufModulePreparedFunc prepared_func,
69                                   GdkPixbufModuleUpdatedFunc updated_func,
70                                   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  * func - called when we have pixmap created (but no image data)
81  * user_data - passed as arg 1 to func
82  * return context (opaque to user)
83  */
84
85 static gpointer
86 gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func, 
87                                   GdkPixbufModulePreparedFunc prepared_func,
88                                   GdkPixbufModuleUpdatedFunc updated_func,
89                                   gpointer user_data,
90                                   GError **error)
91 {
92         struct wbmp_progressive_state *context;
93
94         context = g_new0(struct wbmp_progressive_state, 1);
95         context->prepared_func = prepared_func;
96         context->updated_func = updated_func;
97         context->user_data = user_data;
98
99         context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
100         context->call_progressive_updates = TRUE;
101         context->pixbuf = NULL;
102
103         return (gpointer) context;
104 }
105
106 /*
107  * context - returned from image_begin_load
108  *
109  * free context, unref gdk_pixbuf
110  */
111 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
112                                                  GError **error)
113 {
114         struct wbmp_progressive_state *context =
115             (struct wbmp_progressive_state *) data;
116
117         /* FIXME this thing needs to report errors if
118          * we have unused image data
119          */
120         
121         g_return_val_if_fail(context != NULL, TRUE);
122         if (context->pixbuf)
123           g_object_unref(context->pixbuf);
124
125         g_free(context);
126
127         return TRUE;
128 }
129
130 static gboolean
131 getin(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
132 {
133   int last_num, buf_num;
134
135   if((context->last_len + *buf_size) < datum_size)
136     return FALSE;
137
138   /* We know we can pull it out of there */
139   last_num = MIN(datum_size, context->last_len);
140   buf_num = MIN(datum_size-last_num, *buf_size);
141   memcpy(ptr, context->last_buf, last_num);
142   memcpy(ptr+last_num, *buf, buf_num);
143          
144   context->last_len -= last_num;
145   if(context->last_len)
146     memmove(context->last_buf, context->last_buf+last_num, context->last_len);
147   *buf_size -= buf_num;
148   *buf += buf_num;
149
150   return TRUE;
151 }
152
153 static gboolean
154 save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
155 {
156   if(buf_size > (sizeof(context->last_buf) - context->last_len))
157     return FALSE;
158
159   memcpy(context->last_buf+context->last_len, buf, buf_size);
160   context->last_len += buf_size;
161
162   return TRUE;
163 }
164
165 static gboolean
166 get_mbi(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, int *val)
167 {
168   guchar intbuf[16];
169   int n;
170   gboolean rv;
171
172   *val = 0;
173   n = 0;
174   do {
175     rv = getin(context, buf, buf_size, intbuf+n, 1);
176     if(!rv)
177       goto out;
178     *val <<= 7;
179     *val |= intbuf[n] & 0x7F;
180     n++;
181   } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
182
183  out:
184   if(!rv || (intbuf[n-1] & 0x80))
185     {
186       rv = save_rest(context, intbuf, n);
187
188       if(!rv)
189         g_error("Couldn't save_rest of intbuf");
190       return FALSE;
191     }
192
193   return TRUE;
194 }
195
196 /*
197  * context - from image_begin_load
198  * buf - new image data
199  * size - length of new image data
200  *
201  * append image data onto inrecrementally built output image
202  */
203 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
204                                                       const guchar * buf,
205                                                       guint size, GError **error)
206 {
207         struct wbmp_progressive_state *context =
208             (struct wbmp_progressive_state *) data;
209         gboolean bv = FALSE;
210
211         do
212           {
213             if(context->need_type)
214               {
215                 guchar val;
216
217                 bv = getin(context, &buf, &size, &val, 1);
218                 if(bv)
219                   {
220                     context->type = val;
221                     context->need_type = FALSE;
222                   }
223               }
224             else if(context->need_header)
225               {
226                 guchar val;
227
228                 bv = getin(context, &buf, &size, &val, 1);
229                 if(bv)
230                   {
231                     /* We skip over the extended header - val is unused */
232                     if(!(val & 0x80))
233                       context->need_header = FALSE;
234                   }
235               }
236             else if(context->need_width)
237               {
238                 bv = get_mbi(context, &buf, &size, &context->width);
239                 if(bv) {
240                   context->need_width = FALSE;
241
242                   if (context->width <= 0) {
243                     g_set_error_literal (error,
244                                          GDK_PIXBUF_ERROR,
245                                          GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
246                                          _("Image has zero width"));
247
248                     return FALSE;
249                   }
250                 }
251                 
252               }
253             else if(context->need_height)
254               {
255                 bv = get_mbi(context, &buf, &size, &context->height);
256                 if(bv)
257                   {
258                     context->need_height = FALSE;
259
260                     if (context->height <= 0) {
261                       g_set_error_literal (error,
262                                            GDK_PIXBUF_ERROR,
263                                            GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
264                                            _("Image has zero height"));
265                       
266                       return FALSE;
267                     }
268
269                     context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
270                     
271                     if (!context->pixbuf) {
272                       g_set_error_literal (error,
273                                            GDK_PIXBUF_ERROR,
274                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
275                                            _("Not enough memory to load image"));
276                       return FALSE;
277                     }
278
279
280                     if(context->prepared_func)
281                       context->prepared_func(context->pixbuf, NULL, context->user_data);
282                   }
283               }
284             else if(context->needmore)
285               {
286                 int first_row;
287                 first_row = context->cury;
288                 for( ; context->cury < context->height; context->cury++, context->curx = 0)
289                   {
290                     for( ; context->curx < context->width; context->curx += 8)
291                       {
292                         guchar byte;
293                         guchar *ptr;
294                         int xoff;
295                         bv = getin(context, &buf, &size, &byte, 1);
296                         if(!bv)
297                           goto out;
298
299                         ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
300                         for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
301                           {
302                             guchar pixval;
303
304                             if (context->curx + (7 - xoff) == context->width)
305                               break;
306
307                             if(byte & (1<<xoff))
308                               pixval = 0xFF;
309                             else
310                               pixval = 0x0;
311
312                             ptr[0] = ptr[1] = ptr[2] = pixval;
313                           }
314                       }
315                   }
316                 context->needmore = FALSE;
317
318               out:
319                 if(context->updated_func)
320                   context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
321                                         context->user_data);
322               }
323             else
324               bv = FALSE; /* Nothing left to do, stop feeding me data! */
325
326           } while(bv);
327
328         if(size) {
329           bv = save_rest(context, buf, size);
330           if (!bv) {
331               g_set_error_literal (error,
332                                    GDK_PIXBUF_ERROR,
333                                    GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
334                                    _("Couldn't save the rest"));
335
336               return FALSE;
337           }
338         }
339         return TRUE;
340 }
341
342 #ifndef INCLUDE_wbmp
343 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
344 #else
345 #define MODULE_ENTRY(function) void _gdk_pixbuf__wbmp_ ## function
346 #endif
347
348 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
349 {
350         module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
351         module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
352         module->load_increment = gdk_pixbuf__wbmp_image_load_increment;
353 }
354
355 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
356 {
357         static GdkPixbufModulePattern signature[] = {
358                 { "  ",    "zz", 1 }, 
359                 { " \140", "z ", 1 },
360                 { " \100", "z ", 1 },
361                 { " \040", "z ", 1 },
362                 { NULL, NULL, 0 }
363         };
364         static gchar * mime_types[] = {
365                 "image/vnd.wap.wbmp",
366                 NULL
367         };
368         static gchar * extensions[] = {
369                 "wbmp",
370                 NULL
371         };
372
373         info->name = "wbmp";
374         info->signature = signature;
375         info->description = N_("The WBMP image format");
376         info->mime_types = mime_types;
377         info->extensions = extensions;
378         info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
379         info->license = "LGPL";
380 }