]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixdata.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / gdk-pixbuf / gdk-pixdata.c
1 /* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
2  * Copyright (C) 1999, 2001 Tim Janik
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <config.h>
20 #include "gdk-pixdata.h"
21
22 #include "gdk-pixbuf-private.h"
23 #include <string.h>
24
25 #define APPEND g_string_append_printf
26
27 /* --- functions --- */
28 static guint
29 pixdata_get_length (const GdkPixdata *pixdata)
30 {
31   guint bpp, length;
32
33   if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
34     bpp = 3;
35   else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
36     bpp = 4;
37   else
38     return 0;   /* invalid format */
39   switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
40     {
41       guint8 *rle_buffer;
42       guint max_length;
43     case GDK_PIXDATA_ENCODING_RAW:
44       length = pixdata->rowstride * pixdata->height;
45       break;
46     case GDK_PIXDATA_ENCODING_RLE:
47       /* need an RLE walk to determine size */
48       max_length = pixdata->rowstride * pixdata->height;
49       rle_buffer = pixdata->pixel_data;
50       length = 0;
51       while (length < max_length)
52         {
53           guint chunk_length = *(rle_buffer++);
54
55           if (chunk_length & 128)
56             {
57               chunk_length = chunk_length - 128;
58               if (!chunk_length)        /* RLE data corrupted */
59                 return 0;
60               length += chunk_length * bpp;
61               rle_buffer += bpp;
62             }
63           else
64             {
65               if (!chunk_length)        /* RLE data corrupted */
66                 return 0;
67               chunk_length *= bpp;
68               length += chunk_length;
69               rle_buffer += chunk_length;
70             }
71         }
72       length = rle_buffer - pixdata->pixel_data;
73       break;
74     default:
75       length = 0;
76       break;
77     }
78   return length;
79 }
80
81 /**
82  * gdk_pixdata_serialize:
83  * @pixdata: a valid #GdkPixdata structure to serialize.
84  * @stream_length_p: location to store the resulting stream length in.
85  *
86  * Serializes a #GdkPixdata structure into a byte stream.
87  * The byte stream consists of a straightforward writeout of the
88  * #GdkPixdata fields in network byte order, plus the @pixel_data
89  * bytes the structure points to.
90  *
91  * Return value: A newly-allocated string containing the serialized
92  * #GdkPixdata structure.
93  **/
94 guint8* /* free result */
95 gdk_pixdata_serialize (const GdkPixdata *pixdata,
96                        guint            *stream_length_p)
97 {
98   guint8 *stream, *s;
99   guint32 *istream;
100   guint length;
101
102   /* check args passing */
103   g_return_val_if_fail (pixdata != NULL, NULL);
104   g_return_val_if_fail (stream_length_p != NULL, NULL);
105   /* check pixdata contents */
106   g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
107   g_return_val_if_fail (pixdata->width > 0, NULL);
108   g_return_val_if_fail (pixdata->height > 0, NULL);
109   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
110   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
111                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
112   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
113   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
114                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
115   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
116
117   length = pixdata_get_length (pixdata);
118
119   /* check length field */
120   g_return_val_if_fail (length != 0, NULL);
121   
122   stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
123   istream = (guint32*) stream;
124
125   /* store header */
126   *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
127   *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
128   *istream++ = g_htonl (pixdata->pixdata_type);
129   *istream++ = g_htonl (pixdata->rowstride);
130   *istream++ = g_htonl (pixdata->width);
131   *istream++ = g_htonl (pixdata->height);
132
133   /* copy pixel data */
134   s = (guint8*) istream;
135   memcpy (s, pixdata->pixel_data, length);
136   s += length;
137
138   *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
139   g_assert (s - stream == *stream_length_p);    /* paranoid */
140
141   return stream;
142 }
143
144 #define return_header_corrupt(error)    { \
145   g_set_error (error, GDK_PIXBUF_ERROR, \
146                GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image header corrupt")); \
147   return FALSE; \
148 }
149 #define return_invalid_format(error)    { \
150   g_set_error (error, GDK_PIXBUF_ERROR, \
151                GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image format unknown")); \
152   return FALSE; \
153 }
154 #define return_pixel_corrupt(error)     { \
155   g_set_error (error, GDK_PIXBUF_ERROR, \
156                GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); \
157   return FALSE; \
158 }
159
160 static inline const guint8 *
161 get_uint32 (const guint8 *stream, guint *result)
162 {
163   *result = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
164   return stream + 4;
165 }
166
167 /**
168  * gdk_pixdata_deserialize:
169  * @pixdata: a #GdkPixdata structure to be filled in.
170  * @stream_length: length of the stream used for deserialization.
171  * @stream: stream of bytes containing a serialized #GdkPixdata structure.
172  * @error: #GError location to indicate failures (maybe %NULL to ignore errors).
173  *
174  * Deserializes (reconstruct) a #GdkPixdata structure from a byte stream.
175  * The byte stream consists of a straightforward writeout of the
176  * #GdkPixdata fields in network byte order, plus the @pixel_data
177  * bytes the structure points to.
178  * The @pixdata contents are reconstructed byte by byte and are checked
179  * for validity. This function may fail with %GDK_PIXBUF_CORRUPT_IMAGE
180  * or %GDK_PIXBUF_ERROR_UNKNOWN_TYPE.
181  *
182  * Return value: Upon successful deserialization %TRUE is returned,
183  * %FALSE otherwise.
184  **/
185 gboolean
186 gdk_pixdata_deserialize (GdkPixdata   *pixdata,
187                          guint         stream_length,
188                          const guint8 *stream,
189                          GError      **error)
190 {
191   guint color_type, sample_width, encoding;
192
193   g_return_val_if_fail (pixdata != NULL, FALSE);
194   if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
195     return_header_corrupt (error);
196   g_return_val_if_fail (stream != NULL, FALSE);
197
198
199   /* deserialize header */
200   stream = get_uint32 (stream, &pixdata->magic);
201   stream = get_uint32 (stream, (guint32 *)&pixdata->length);
202   if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
203     return_header_corrupt (error);
204   stream = get_uint32 (stream, &pixdata->pixdata_type);
205   stream = get_uint32 (stream, &pixdata->rowstride);
206   stream = get_uint32 (stream, &pixdata->width);
207   stream = get_uint32 (stream, &pixdata->height);
208   if (pixdata->width < 1 || pixdata->height < 1 ||
209       pixdata->rowstride < pixdata->width)
210     return_header_corrupt (error);
211   color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
212   sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
213   encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
214   if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
215        color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
216       sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
217       (encoding != GDK_PIXDATA_ENCODING_RAW &&
218        encoding != GDK_PIXDATA_ENCODING_RLE))
219     return_invalid_format (error);
220
221   /* deserialize pixel data */
222   if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
223     return_pixel_corrupt (error);
224   pixdata->pixel_data = (guint8 *)stream;
225
226   return TRUE;
227 }
228
229 static gboolean
230 diff2_rgb (guint8 *ip)
231 {
232   return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
233 }
234
235 static gboolean
236 diff2_rgba (guint8 *ip)
237 {
238   return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
239 }
240
241 static guint8*                  /* dest buffer bound */
242 rl_encode_rgbx (guint8 *bp,     /* dest buffer */
243                 guint8 *ip,     /* image pointer */
244                 guint8 *limit,  /* image upper bound */
245                 guint   n_ch)
246 {
247   gboolean (*diff2_pix) (guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
248   guint8 *ilimit = limit - n_ch;
249
250   while (ip < limit)
251     {
252       g_assert (ip < ilimit); /* paranoid */
253
254       if (diff2_pix (ip))
255         {
256           guint8 *s_ip = ip;
257           guint l = 1;
258
259           ip += n_ch;
260           while (l < 127 && ip < ilimit && diff2_pix (ip))
261             { ip += n_ch; l += 1; }
262           if (ip == ilimit && l < 127)
263             { ip += n_ch; l += 1; }
264           *(bp++) = l;
265           memcpy (bp, s_ip, l * n_ch);
266           bp += l * n_ch;
267         }
268       else
269         {
270           guint l = 2;
271
272           ip += n_ch;
273           while (l < 127 && ip < ilimit && !diff2_pix (ip))
274             { ip += n_ch; l += 1; }
275           *(bp++) = l | 128;
276           memcpy (bp, ip, n_ch);
277           ip += n_ch;
278           bp += n_ch;
279         }
280       if (ip == ilimit)
281         {
282           *(bp++) = 1;
283           memcpy (bp, ip, n_ch);
284           ip += n_ch;
285           bp += n_ch;
286         }
287     }
288
289   return bp;
290 }
291
292 /**
293  * gdk_pixdata_from_pixbuf:
294  * @pixdata: a #GdkPixdata to fill.
295  * @pixbuf: the data to fill @pixdata with.
296  * @use_rle: whether to use run-length encoding for the pixel data.
297  *
298  * Converts a #GdkPixbuf to a #GdkPixdata. If @use_rle is %TRUE, the
299  * pixel data is run-length encoded into newly-allocated memory and a 
300  * pointer to that memory is returned. 
301  *
302  * Returns: If @ure_rle is %TRUE, a pointer to the newly-allocated memory 
303  *   for the run-length encoded pixel data, otherwise %NULL.
304  **/
305 gpointer
306 gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
307                          const GdkPixbuf *pixbuf,
308                          gboolean         use_rle)
309 {
310   gpointer free_me = NULL;
311   guint height, rowstride, encoding, bpp, length;
312   guint8 *img_buffer;
313
314   g_return_val_if_fail (pixdata != NULL, NULL);
315   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
316   g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
317   g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
318                         (pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
319   g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
320
321   height = pixbuf->height;
322   rowstride = pixbuf->rowstride;
323   encoding = use_rle ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
324   bpp = pixbuf->has_alpha ? 4 : 3;
325
326   if (encoding == GDK_PIXDATA_ENCODING_RLE)
327     {
328       guint pad, n_bytes = rowstride * height;
329       guint8 *img_buffer_end, *data;
330
331       pad = rowstride;
332       pad = MAX (pad, 130 + n_bytes / 127);
333       data = g_new (guint8, pad + n_bytes);
334       free_me = data;
335       img_buffer = data;
336       img_buffer_end = rl_encode_rgbx (img_buffer,
337                                        pixbuf->pixels, pixbuf->pixels + n_bytes,
338                                        bpp);
339       length = img_buffer_end - img_buffer;
340     }
341   else
342     {
343       img_buffer = pixbuf->pixels;
344       length = rowstride * height;
345     }
346
347   pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
348   pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
349   pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
350   pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
351   pixdata->pixdata_type |= encoding;
352   pixdata->rowstride = rowstride;
353   pixdata->width = pixbuf->width;
354   pixdata->height = height;
355   pixdata->pixel_data = img_buffer;
356
357   return free_me;
358 }
359
360 /**
361  * gdk_pixbuf_from_pixdata:
362  * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
363  * @copy_pixels: whether to copy raw pixel data; run-length encoded
364  *     pixel data is always copied.
365  * @error: location to store possible errors.
366  * 
367  * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or
368  * if the pixel data is run-length-encoded, the pixel data is copied into
369  * newly-allocated memory; otherwise it is reused.
370  *
371  * Returns: a new #GdkPixbuf.
372  **/
373 GdkPixbuf*
374 gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
375                          gboolean          copy_pixels,
376                          GError          **error)
377 {
378   guint encoding, bpp;
379   guint8 *data = NULL;
380
381   g_return_val_if_fail (pixdata != NULL, NULL);
382   g_return_val_if_fail (pixdata->width > 0, NULL);
383   g_return_val_if_fail (pixdata->height > 0, NULL);
384   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
385   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
386                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
387   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
388   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
389                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
390   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
391
392   bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
393   encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
394   if (encoding == GDK_PIXDATA_ENCODING_RLE)
395     copy_pixels = TRUE;
396   if (copy_pixels)
397     {
398       data = g_try_malloc (pixdata->rowstride * pixdata->height);
399       if (!data)
400         {
401           g_set_error (error, GDK_PIXBUF_ERROR,
402                        GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
403                        ngettext("failed to allocate image buffer of %u byte",
404                                 "failed to allocate image buffer of %u bytes",
405                                 pixdata->rowstride * pixdata->height),
406                        pixdata->rowstride * pixdata->height);
407           return NULL;
408         }
409     }
410   if (encoding == GDK_PIXDATA_ENCODING_RLE)
411     {
412       const guint8 *rle_buffer = pixdata->pixel_data;
413       guint8 *image_buffer = data;
414       guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
415       gboolean check_overrun = FALSE;
416
417       while (image_buffer < image_limit)
418         {
419           guint length = *(rle_buffer++);
420
421           if (length & 128)
422             {
423               length = length - 128;
424               check_overrun = image_buffer + length * bpp > image_limit;
425               if (check_overrun)
426                 length = (image_limit - image_buffer) / bpp;
427               if (bpp < 4)      /* RGB */
428                 do
429                   {
430                     memcpy (image_buffer, rle_buffer, 3);
431                     image_buffer += 3;
432                   }
433                 while (--length);
434               else              /* RGBA */
435                 do
436                   {
437                     memcpy (image_buffer, rle_buffer, 4);
438                     image_buffer += 4;
439                   }
440                 while (--length);
441               rle_buffer += bpp;
442             }
443           else
444             {
445               length *= bpp;
446               check_overrun = image_buffer + length > image_limit;
447               if (check_overrun)
448                 length = image_limit - image_buffer;
449               memcpy (image_buffer, rle_buffer, length);
450               image_buffer += length;
451               rle_buffer += length;
452             }
453         }
454       if (check_overrun)
455         {
456           g_free (data);
457           g_set_error (error, GDK_PIXBUF_ERROR,
458                        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
459                        _("Image pixel data corrupt"));
460           return NULL;
461         }
462     }
463   else if (copy_pixels)
464     memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
465   else
466     data = pixdata->pixel_data;
467
468   return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
469                                    (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
470                                    8, pixdata->width, pixdata->height, pixdata->rowstride,
471                                    copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
472 }
473
474 typedef struct {
475   /* config */
476   gboolean     dump_stream;
477   gboolean     dump_struct;
478   gboolean     dump_macros;
479   gboolean     dump_gtypes;
480   gboolean     dump_rle_decoder;
481   const gchar *static_prefix;
482   const gchar *const_prefix;
483   /* runtime */
484   GString *gstring;
485   guint    pos;
486   gboolean pad;
487 } CSourceData;
488
489 static inline void
490 save_uchar (CSourceData *cdata,
491             guint8       d)
492 {
493   GString *gstring = cdata->gstring;
494
495   if (cdata->pos > 70)
496     {
497       if (cdata->dump_struct || cdata->dump_stream)
498         {
499           g_string_append (gstring, "\"\n  \"");
500           cdata->pos = 3;
501           cdata->pad = FALSE;
502         }
503       if (cdata->dump_macros)
504         {
505           g_string_append (gstring, "\" \\\n  \"");
506           cdata->pos = 3;
507           cdata->pad = FALSE;
508         }
509     }
510   if (d < 33 || d > 126 || d == '?')
511     {
512       APPEND (gstring, "\\%o", d);
513       cdata->pos += 1 + 1 + (d > 7) + (d > 63);
514       cdata->pad = d < 64;
515       return;
516     }
517   if (d == '\\')
518     {
519       g_string_append (gstring, "\\\\");
520       cdata->pos += 2;
521     }
522   else if (d == '"')
523     {
524       g_string_append (gstring, "\\\"");
525       cdata->pos += 2;
526     }
527   else if (cdata->pad && d >= '0' && d <= '9')
528     {
529       g_string_append (gstring, "\"\"");
530       g_string_append_c (gstring, d);
531       cdata->pos += 3;
532     }
533   else
534     {
535       g_string_append_c (gstring, d);
536       cdata->pos += 1;
537     }
538   cdata->pad = FALSE;
539   return;
540 }
541
542 static inline void
543 save_rle_decoder (GString     *gstring,
544                   const gchar *macro_name,
545                   const gchar *s_uint,
546                   const gchar *s_uint_8,
547                   guint        n_ch)
548 {
549   APPEND (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
550           macro_name);
551   APPEND (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
552   APPEND (gstring, "  __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
553   
554   APPEND (gstring, "  __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
555   
556   APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
557   APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
558   APPEND (gstring, "        do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
559   APPEND (gstring, "      } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
560   APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
561   
562   APPEND (gstring, "  } else { /* RGB */ \\\n");
563   
564   APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
565   APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
566   APPEND (gstring, "        do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
567   APPEND (gstring, "      } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
568   APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
569   
570   APPEND (gstring, "  } } while (0)\n");
571 }
572
573 /**
574  * gdk_pixdata_to_csource:
575  * @pixdata: a #GdkPixdata to convert to C source.
576  * @name: used for naming generated data structures or macros.
577  * @dump_type: a #GdkPixdataDumpType determining the kind of C
578  *   source to be generated.
579  *
580  * Generates C source code suitable for compiling images directly 
581  * into programs. 
582  *
583  * GTK+ ships with a program called <command>gdk-pixbuf-csource</command> 
584  * which offers a command line interface to this function.
585  *
586  * Returns: a newly-allocated string containing the C source form
587  *   of @pixdata.
588  **/
589 GString*
590 gdk_pixdata_to_csource (GdkPixdata        *pixdata,
591                         const gchar       *name,
592                         GdkPixdataDumpType dump_type)
593 {
594   CSourceData cdata = { 0, };
595   gchar *s_uint_8, *s_uint_32, *s_uint, *s_char, *s_null;
596   guint bpp, width, height, rowstride;
597   gboolean rle_encoded;
598   gchar *macro_name;
599   guint8 *img_buffer, *img_buffer_end, *stream = NULL;
600   guint stream_length;
601   GString *gstring;
602   
603   /* check args passing */
604   g_return_val_if_fail (pixdata != NULL, NULL);
605   g_return_val_if_fail (name != NULL, NULL);
606   /* check pixdata contents */
607   g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
608   g_return_val_if_fail (pixdata->width > 0, NULL);
609   g_return_val_if_fail (pixdata->height > 0, NULL);
610   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
611   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
612                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
613   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
614   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
615                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
616   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
617
618   img_buffer = pixdata->pixel_data;
619   if (pixdata->length < 1)
620     img_buffer_end = img_buffer + pixdata_get_length (pixdata);
621   else
622     img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
623   g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
624
625   bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
626   width = pixdata->width;
627   height = pixdata->height;
628   rowstride = pixdata->rowstride;
629   rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
630   macro_name = g_ascii_strup (name, -1);
631
632   cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
633   cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
634   cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
635   g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
636
637   cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
638   cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
639   cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
640   cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
641   gstring = g_string_new (NULL);
642   cdata.gstring = gstring;
643
644   if (!cdata.dump_macros && cdata.dump_gtypes)
645     {
646       s_uint_8 =  "guint8 ";
647       s_uint_32 = "guint32";
648       s_uint =    "guint  ";
649       s_char =    "gchar  ";
650       s_null =    "NULL";
651     }
652   else if (!cdata.dump_macros)
653     {
654       s_uint_8 =  "unsigned char";
655       s_uint_32 = "unsigned int ";
656       s_uint =    "unsigned int ";
657       s_char =    "char         ";
658       s_null =    "(char*) 0";
659     }
660   else if (cdata.dump_macros && cdata.dump_gtypes)
661     {
662       s_uint_8 =  "guint8";
663       s_uint_32 = "guint32";
664       s_uint  =   "guint";
665       s_char =    "gchar";
666       s_null =    "NULL";
667     }
668   else /* cdata.dump_macros && !cdata.dump_gtypes */
669     {
670       s_uint_8 =  "unsigned char";
671       s_uint_32 = "unsigned int";
672       s_uint =    "unsigned int";
673       s_char =    "char";
674       s_null =    "(char*) 0";
675     }
676
677   /* initial comment
678    */
679   APPEND (gstring,
680           "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
681           bpp > 3 ? "RGBA" : "RGB",
682           rle_encoded ? "1-byte-run-length-encoded " : "");
683   
684   /* dump RLE decoder for structures
685    */
686   if (cdata.dump_rle_decoder && cdata.dump_struct)
687     save_rle_decoder (gstring,
688                       macro_name,
689                       cdata.dump_gtypes ? "guint" : "unsigned int",
690                       cdata.dump_gtypes ? "guint8" : "unsigned char",
691                       bpp);
692
693   /* format & size blurbs
694    */
695   if (cdata.dump_macros)
696     {
697       APPEND (gstring, "#define %s_ROWSTRIDE (%u)\n",
698               macro_name, rowstride);
699       APPEND (gstring, "#define %s_WIDTH (%u)\n",
700               macro_name, width);
701       APPEND (gstring, "#define %s_HEIGHT (%u)\n",
702               macro_name, height);
703       APPEND (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
704               macro_name, bpp);
705     }
706   if (cdata.dump_struct)
707     {
708       APPEND (gstring, "%s%sGdkPixdata %s = {\n",
709               cdata.static_prefix, cdata.const_prefix, name);
710       APPEND (gstring, "  0x%x, /* Pixbuf magic: 'GdkP' */\n",
711               GDK_PIXBUF_MAGIC_NUMBER);
712       APPEND (gstring, "  %u + %lu, /* header length + pixel_data length */\n",
713               GDK_PIXDATA_HEADER_LENGTH,
714               rle_encoded ? (glong)(img_buffer_end - img_buffer) : (glong)rowstride * height);
715       APPEND (gstring, "  0x%x, /* pixdata_type */\n",
716               pixdata->pixdata_type);
717       APPEND (gstring, "  %u, /* rowstride */\n",
718               rowstride);
719       APPEND (gstring, "  %u, /* width */\n",
720               width);
721       APPEND (gstring, "  %u, /* height */\n",
722               height);
723       APPEND (gstring, "  /* pixel_data: */\n");
724     }
725   if (cdata.dump_stream)
726     {
727       guint pix_length = img_buffer_end - img_buffer;
728       
729       stream = gdk_pixdata_serialize (pixdata, &stream_length);
730       img_buffer = stream;
731       img_buffer_end = stream + stream_length;
732
733       APPEND (gstring, "#ifdef __SUNPRO_C\n");
734       APPEND (gstring, "#pragma align 4 (%s)\n", name);   
735       APPEND (gstring, "#endif\n");
736
737       APPEND (gstring, "#ifdef __GNUC__\n");
738       APPEND (gstring, "%s%s%s %s[] __attribute__ ((__aligned__ (4))) = \n",
739               cdata.static_prefix, cdata.const_prefix,
740               cdata.dump_gtypes ? "guint8" : "unsigned char",
741               name);
742       APPEND (gstring, "#else\n");
743       APPEND (gstring, "%s%s%s %s[] = \n",
744               cdata.static_prefix, cdata.const_prefix,
745               cdata.dump_gtypes ? "guint8" : "unsigned char",
746               name);
747       APPEND (gstring, "#endif\n");
748
749       APPEND (gstring, "{ \"\"\n  /* Pixbuf magic (0x%x) */\n  \"",
750               GDK_PIXBUF_MAGIC_NUMBER);
751       cdata.pos = 3;
752       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
753       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
754       APPEND (gstring, "\"\n  /* length: header (%u) + pixel_data (%u) */\n  \"",
755               GDK_PIXDATA_HEADER_LENGTH,
756               rle_encoded ? pix_length : rowstride * height);
757       cdata.pos = 3;
758       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
759       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
760       APPEND (gstring, "\"\n  /* pixdata_type (0x%x) */\n  \"",
761               pixdata->pixdata_type);
762       cdata.pos = 3;
763       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
764       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
765       APPEND (gstring, "\"\n  /* rowstride (%u) */\n  \"",
766               rowstride);
767       cdata.pos = 3;
768       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
769       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
770       APPEND (gstring, "\"\n  /* width (%u) */\n  \"", width);
771       cdata.pos = 3;
772       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
773       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
774       APPEND (gstring, "\"\n  /* height (%u) */\n  \"", height);
775       cdata.pos = 3;
776       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
777       save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
778       APPEND (gstring, "\"\n  /* pixel_data: */\n");
779     }
780
781   /* pixel_data intro
782    */
783   if (cdata.dump_macros)
784     {
785       APPEND (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
786               macro_name,
787               rle_encoded ? "RLE_" : "",
788               s_uint_8);
789       APPEND (gstring, "  \"");
790       cdata.pos = 2;
791     }
792   if (cdata.dump_struct)
793     {
794       APPEND (gstring, "  \"");
795       cdata.pos = 3;
796     }
797   if (cdata.dump_stream)
798     {
799       APPEND (gstring, "  \"");
800       cdata.pos = 3;
801     }
802     
803   /* pixel_data
804    */
805   do
806     save_uchar (&cdata, *img_buffer++);
807   while (img_buffer < img_buffer_end);
808
809   /* pixel_data trailer
810    */
811   if (cdata.dump_macros)
812     APPEND (gstring, "\")\n\n");
813   if (cdata.dump_struct)
814     APPEND (gstring, "\",\n};\n\n");
815   if (cdata.dump_stream)
816     APPEND (gstring, "\"};\n\n");
817
818   /* dump RLE decoder for macros
819    */
820   if (cdata.dump_rle_decoder && cdata.dump_macros)
821     save_rle_decoder (gstring,
822                       macro_name,
823                       cdata.dump_gtypes ? "guint" : "unsigned int",
824                       cdata.dump_gtypes ? "guint8" : "unsigned char",
825                       bpp);
826
827   /* cleanup
828    */
829   g_free (stream);
830   g_free (macro_name);
831     
832   return gstring;
833 }
834
835 /**
836  * gdk_pixbuf_new_from_inline:
837  * @data_length: Length in bytes of the @data argument or -1 to 
838  *    disable length checks
839  * @data: Byte data containing a serialized #GdkPixdata structure
840  * @copy_pixels: Whether to copy the pixel data, or use direct pointers
841  *               @data for the resulting pixbuf
842  * @error: #GError return location, may be %NULL to ignore errors
843  *
844  * Create a #GdkPixbuf from a flat representation that is suitable for
845  * storing as inline data in a program. This is useful if you want to
846  * ship a program with images, but don't want to depend on any
847  * external files.
848  *
849  * GTK+ ships with a program called <command>gdk-pixbuf-csource</command> 
850  * which allows for conversion of #GdkPixbufs into such a inline representation.
851  * In almost all cases, you should pass the <option>--raw</option> flag to
852  * <command>gdk-pixbuf-csource</command>. A sample invocation would be:
853  *
854  * <informalexample><programlisting>
855  *  gdk-pixbuf-csource --raw --name=myimage_inline myimage.png
856  * </programlisting></informalexample>
857  * 
858  * For the typical case where the inline pixbuf is read-only static data,
859  * you don't need to copy the pixel data unless you intend to write to
860  * it, so you can pass %FALSE for @copy_pixels.  (If you pass 
861  * <option>--rle</option> to <command>gdk-pixbuf-csource</command>, a copy 
862  * will be made even if @copy_pixels is %FALSE, so using this option is 
863  * generally a bad idea.)
864  *
865  * If you create a pixbuf from const inline data compiled into your
866  * program, it's probably safe to ignore errors and disable length checks, 
867  * since things will always succeed:
868  * <informalexample><programlisting>
869  * pixbuf = gdk_pixbuf_new_from_inline (-1, myimage_inline, FALSE, NULL);
870  * </programlisting></informalexample>
871  *
872  * For non-const inline data, you could get out of memory. For untrusted 
873  * inline data located at runtime, you could have corrupt inline data in 
874  * addition.
875  *
876  * Return value: A newly-created #GdkPixbuf structure with a reference,
877  *   count of 1, or %NULL if an error occurred.
878  **/
879 GdkPixbuf*
880 gdk_pixbuf_new_from_inline (gint          data_length,
881                             const guint8 *data,
882                             gboolean      copy_pixels,
883                             GError      **error)
884 {
885   GdkPixdata pixdata;
886
887   if (data_length != -1)
888     g_return_val_if_fail (data_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
889   g_return_val_if_fail (data != NULL, NULL);
890
891   if (!gdk_pixdata_deserialize (&pixdata, data_length, data, error))
892     return NULL;
893
894   return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
895 }