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