Bug Summary

File:_build/../cdk-pixbuf/io-png.c
Warning:line 1079, column 28
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name io-png.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-21/lib/clang/21 -I cdk-pixbuf/libstaticpixbufloader-png.a.p -I cdk-pixbuf -I ../cdk-pixbuf -I . -I .. -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/librsvg-2.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/cairo -I /usr/include/libxml2 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D _FILE_OFFSET_BITS=64 -D _POSIX_C_SOURCE=200809L -D _DEFAULT_SOURCE -D _XOPEN_SOURCE=700 -D HAVE_CONFIG_H=1 -D G_LOG_STRUCTURED=1 -D G_LOG_DOMAIN="CdkPixbuf" -D CDK_PIXBUF_COMPILATION -D CDK_PIXBUF_PREFIX="/usr/local" -D CDK_PIXBUF_LOCALEDIR="/usr/local/share/locale" -D CDK_PIXBUF_LIBDIR="/usr/local/lib/x86_64-linux-gnu" -D CDK_PIXBUF_BINARY_VERSION="2.10.0" -D CDK_PIXBUF_ENABLE_BACKEND -D PIXBUF_LIBDIR="/usr/local/lib/x86_64-linux-gnu/cdk-pixbuf-2.0/2.10.0/loaders" -D BUILT_MODULES_DIR="/rootdir/_build/cdk-pixbuf" -D INCLUDE_png -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-int-conversion -Wno-uninitialized -Wno-discarded-qualifiers -std=gnu99 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2026-06-03-092842-8532-1 -x c ../cdk-pixbuf/io-png.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/* CdkPixbuf library - PNG image loader
3 *
4 * Copyright (C) 1999 Mark Crichton
5 * Copyright (C) 1999 The Free Software Foundation
6 *
7 * Authors: Mark Crichton <crichton@gimp.org>
8 * Federico Mena-Quintero <federico@gimp.org>
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, see <http://www.gnu.org/licenses/>.
22 */
23
24#include "config.h"
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <png.h>
29#include <math.h>
30#include <glib-object.h>
31#include <glib/gi18n-lib.h>
32
33#include "cdk-pixbuf-core.h"
34#include "cdk-pixbuf-io.h"
35#include "fallback-c89.c"
36
37/* Helper macros to convert between density units */
38#define DPI_TO_DPM(value)((int) round ((value) * 1000 / 25.4)) ((int) round ((value) * 1000 / 25.4))
39#define DPM_TO_DPI(value)((int) round ((value) * 25.4 / 1000)) ((int) round ((value) * 25.4 / 1000))
40
41#define DEFAULT_FILL_COLOR0x979899ff 0x979899ff
42
43#ifndef NO_MODULE_ENTRIES
44static gboolean
45setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr,
46 GError **error,
47 png_uint_32* width_p, png_uint_32* height_p,
48 int* color_type_p)
49{
50 png_uint_32 width, height;
51 int bit_depth, color_type, interlace_type, compression_type, filter_type;
52 int channels;
53
54 /* Get the image info */
55
56 /* Must check bit depth, since png_get_IHDR generates an
57 FPE on bit_depth 0.
58 */
59 bit_depth = png_get_bit_depth (png_read_ptr, png_info_ptr);
60 if (bit_depth < 1 || bit_depth > 16) {
61 g_set_error_literal (error,
62 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
63 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
64 _("Bits per channel of PNG image is invalid.")((char *) g_dgettext ("cdk-pixbuf", "Bits per channel of PNG image is invalid."
))
);
65 return FALSE(0);
66 }
67 png_get_IHDR (png_read_ptr, png_info_ptr,
68 &width, &height,
69 &bit_depth,
70 &color_type,
71 &interlace_type,
72 &compression_type,
73 &filter_type);
74
75 /* set_expand() basically needs to be called unless
76 we are already in RGB/RGBA mode
77 */
78 if (color_type == PNG_COLOR_TYPE_PALETTE(2 | 1) &&
79 bit_depth <= 8) {
80
81 /* Convert indexed images to RGB */
82 png_set_expand (png_read_ptr);
83
84 } else if (color_type == PNG_COLOR_TYPE_GRAY0 &&
85 bit_depth < 8) {
86
87 /* Convert grayscale to RGB */
88 png_set_expand (png_read_ptr);
89
90 } else if (png_get_valid (png_read_ptr,
91 png_info_ptr, PNG_INFO_tRNS0x0010U)) {
92
93 /* If we have transparency header, convert it to alpha
94 channel */
95 png_set_expand(png_read_ptr);
96
97 } else if (bit_depth < 8) {
98
99 /* If we have < 8 scale it up to 8 */
100 png_set_expand(png_read_ptr);
101
102
103 /* Conceivably, png_set_packing() is a better idea;
104 * God only knows how libpng works
105 */
106 }
107
108 /* If we are 16-bit, convert to 8-bit */
109 if (bit_depth == 16) {
110 png_set_strip_16(png_read_ptr);
111 }
112
113 /* If gray scale, convert to RGB */
114 if (color_type == PNG_COLOR_TYPE_GRAY0 ||
115 color_type == PNG_COLOR_TYPE_GRAY_ALPHA(4)) {
116 png_set_gray_to_rgb(png_read_ptr);
117 }
118
119 /* If interlaced, handle that */
120 if (interlace_type != PNG_INTERLACE_NONE0) {
121 png_set_interlace_handling(png_read_ptr);
122 }
123
124 /* Update the info the reflect our transformations */
125 png_read_update_info(png_read_ptr, png_info_ptr);
126
127 png_get_IHDR (png_read_ptr, png_info_ptr,
128 &width, &height,
129 &bit_depth,
130 &color_type,
131 &interlace_type,
132 &compression_type,
133 &filter_type);
134
135 *width_p = width;
136 *height_p = height;
137 *color_type_p = color_type;
138
139 /* Check that the new info is what we want */
140
141 if (width == 0 || height == 0) {
142 g_set_error_literal (error,
143 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
144 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
145 _("Transformed PNG has zero width or height.")((char *) g_dgettext ("cdk-pixbuf", "Transformed PNG has zero width or height."
))
);
146 return FALSE(0);
147 }
148
149 if (bit_depth != 8) {
150 g_set_error_literal (error,
151 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
152 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
153 _("Bits per channel of transformed PNG is not 8.")((char *) g_dgettext ("cdk-pixbuf", "Bits per channel of transformed PNG is not 8."
))
);
154 return FALSE(0);
155 }
156
157 if ( ! (color_type == PNG_COLOR_TYPE_RGB(2) ||
158 color_type == PNG_COLOR_TYPE_RGB_ALPHA(2 | 4)) ) {
159 g_set_error_literal (error,
160 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
161 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
162 _("Transformed PNG not RGB or RGBA.")((char *) g_dgettext ("cdk-pixbuf", "Transformed PNG not RGB or RGBA."
))
);
163 return FALSE(0);
164 }
165
166 channels = png_get_channels(png_read_ptr, png_info_ptr);
167 if ( ! (channels == 3 || channels == 4) ) {
168 g_set_error_literal (error,
169 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
170 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
171 _("Transformed PNG has unsupported number of channels, must be 3 or 4.")((char *) g_dgettext ("cdk-pixbuf", "Transformed PNG has unsupported number of channels, must be 3 or 4."
))
);
172 return FALSE(0);
173 }
174 return TRUE(!(0));
175}
176#endif /* !NO_MODULE_ENTRIES */
177
178static void
179png_simple_error_callback(png_structp png_save_ptr,
180 png_const_charp error_msg)
181{
182 GError **error;
183
184 error = png_get_error_ptr(png_save_ptr);
185
186 /* I don't trust libpng to call the error callback only once,
187 * so check for already-set error
188 */
189 if (error && *error == NULL((void*)0)) {
190 g_set_error (error,
191 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
192 CDK_PIXBUF_ERROR_FAILED,
193 _("Fatal error in PNG image file: %s")((char *) g_dgettext ("cdk-pixbuf", "Fatal error in PNG image file: %s"
))
,
194 error_msg);
195 }
196
197 longjmp (png_jmpbuf(png_save_ptr)(*png_set_longjmp_fn((png_save_ptr), longjmp, (sizeof (jmp_buf
))))
, 1);
198}
199
200static void
201png_simple_warning_callback(png_structp png_save_ptr,
202 png_const_charp warning_msg)
203{
204 /* Don't print anything; we should not be dumping junk to
205 * stderr, since that may be bad for some apps. If it's
206 * important enough to display, we need to add a GError
207 * **warning return location wherever we have an error return
208 * location.
209 */
210}
211
212#ifndef NO_MODULE_ENTRIES
213static gboolean
214png_text_to_pixbuf_option (png_text text_ptr,
215 gchar **key,
216 gchar **value)
217{
218 gboolean is_ascii = TRUE(!(0));
219 int i;
220
221 /* Avoid loading iconv if the text is plain ASCII */
222 for (i = 0; i < text_ptr.text_length; i++)
223 if (text_ptr.text[i] & 0x80) {
224 is_ascii = FALSE(0);
225 break;
226 }
227
228 if (is_ascii) {
229 *value = g_strdup (text_ptr.text)g_strdup_inline (text_ptr.text);
230 } else {
231 *value = g_convert (text_ptr.text, -1,
232 "UTF-8", "ISO-8859-1",
233 NULL((void*)0), NULL((void*)0), NULL((void*)0));
234 }
235
236 if (*value) {
237 *key = g_strconcat ("tEXt::", text_ptr.key, NULL((void*)0));
238 return TRUE(!(0));
239 } else {
240 g_warning ("Couldn't convert text chunk value to UTF-8.");
241 *key = NULL((void*)0);
242 return FALSE(0);
243 }
244}
245#endif /* NO_MODULE_ENTRIES */
246
247#ifndef NO_MODULE_ENTRIES
248static png_voidp
249png_malloc_callback (png_structp o, png_size_t size)
250{
251 return g_try_malloc (size);
252}
253#endif /* !NO_MODULE_ENTRIES */
254
255#ifndef NO_MODULE_ENTRIES
256static void
257png_free_callback (png_structp o, png_voidp x)
258{
259 g_free (x);
260}
261#endif /* !NO_MODULE_ENTRIES */
262
263#ifndef NO_MODULE_ENTRIES
264/* Shared library entry point */
265static CdkPixbuf *
266cdk_pixbuf__png_image_load (FILE *f, GError **error)
267{
268 CdkPixbuf * volatile pixbuf = NULL((void*)0);
269 gint rowstride;
270 png_structp png_ptr;
271 png_infop info_ptr;
272 png_textp text_ptr;
273 gint i, ctype;
274 png_uint_32 w, h;
275 png_bytepp volatile rows = NULL((void*)0);
276 gint num_texts;
277 gchar *key;
278 gchar *value;
279 gchar *icc_profile_base64;
280 const gchar *icc_profile_title;
281 const gchar *icc_profile;
282 png_uint_32 icc_profile_size;
283 png_uint_32 x_resolution;
284 png_uint_32 y_resolution;
285 int unit_type;
286 gchar *density_str;
287 guint32 retval;
288 gint compression_type;
289 gpointer ptr;
290
291#ifdef PNG_USER_MEM_SUPPORTED
292 png_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING"1.6.58",
293 error,
294 png_simple_error_callback,
295 png_simple_warning_callback,
296 NULL((void*)0),
297 png_malloc_callback,
298 png_free_callback);
299#else
300 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING"1.6.58",
301 error,
302 png_simple_error_callback,
303 png_simple_warning_callback);
304#endif
305 if (!png_ptr)
306 return NULL((void*)0);
307
308 info_ptr = png_create_info_struct (png_ptr);
309 if (!info_ptr) {
310 png_destroy_read_struct (&png_ptr, NULL((void*)0), NULL((void*)0));
311 return NULL((void*)0);
312 }
313
314 if (setjmp (png_jmpbuf(png_ptr))_setjmp ((*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf
)))))
) {
315 g_free (rows);
316
317 if (pixbuf)
318 g_object_unref (pixbuf);
319
320 png_destroy_read_struct (&png_ptr, &info_ptr, NULL((void*)0));
321 return NULL((void*)0);
322 }
323
324 png_init_io (png_ptr, f);
325 png_read_info (png_ptr, info_ptr);
326
327 if (!setup_png_transformations(png_ptr, info_ptr, error, &w, &h, &ctype)) {
328 png_destroy_read_struct (&png_ptr, &info_ptr, NULL((void*)0));
329 return NULL((void*)0);
330 }
331
332 pixbuf = cdk_pixbuf_new (CDK_COLORSPACE_RGB, ctype & PNG_COLOR_MASK_ALPHA4, 8, w, h);
333
334 if (!pixbuf) {
335 g_set_error_literal (error,
336 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
337 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
338 _("Insufficient memory to load PNG file")((char *) g_dgettext ("cdk-pixbuf", "Insufficient memory to load PNG file"
))
);
339
340 png_destroy_read_struct (&png_ptr, &info_ptr, NULL((void*)0));
341 return NULL((void*)0);
342 }
343
344 rowstride = cdk_pixbuf_get_rowstride (pixbuf);
345
346 cdk_pixbuf_fill (pixbuf, DEFAULT_FILL_COLOR0x979899ff);
347
348 rows = g_new (png_bytep, h)(png_bytep *) (__extension__ ({ gsize __n = (gsize) (h); gsize
__s = sizeof (png_bytep); gpointer __p; if (__s == 1) __p = g_malloc
(__n); else if (__builtin_constant_p (__n) && (__s ==
0 || __n <= (9223372036854775807L *2UL+1UL) / __s)) __p =
g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p;
}))
;
349
350 for (i = 0, ptr = cdk_pixbuf_get_pixels (pixbuf); i < h; i++, ptr = (guchar *) ptr + rowstride)
351 rows[i] = ptr;
352
353 png_read_image (png_ptr, rows);
354 png_read_end (png_ptr, info_ptr);
355
356 if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_texts)) {
357 for (i = 0; i < num_texts; i++) {
358 png_text_to_pixbuf_option (text_ptr[i], &key, &value);
359 cdk_pixbuf_set_option (pixbuf, key, value);
360 g_free (key);
361 g_free (value);
362 }
363 }
364
365#if defined(PNG_cHRM_SUPPORTED)
366 /* Extract embedded ICC profile */
367 retval = png_get_iCCP (png_ptr, info_ptr,
368 (png_charpp) &icc_profile_title, &compression_type,
369 (png_bytepp) &icc_profile, (png_uint_32*) &icc_profile_size);
370 if (retval != 0) {
371 icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
372 cdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
373 g_free (icc_profile_base64);
374 }
375#endif
376
377#ifdef PNG_pHYs_SUPPORTED
378 retval = png_get_pHYs (png_ptr, info_ptr, &x_resolution, &y_resolution, &unit_type);
379 if (retval != 0 && unit_type == PNG_RESOLUTION_METER1) {
380 density_str = g_strdup_printf ("%d", DPM_TO_DPI (x_resolution)((int) round ((x_resolution) * 25.4 / 1000)));
381 cdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
382 g_free (density_str);
383 density_str = g_strdup_printf ("%d", DPM_TO_DPI (y_resolution)((int) round ((y_resolution) * 25.4 / 1000)));
384 cdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
385 g_free (density_str);
386 }
387#endif
388
389 g_free (rows);
390 png_destroy_read_struct (&png_ptr, &info_ptr, NULL((void*)0));
391
392 return pixbuf;
393}
394#endif /* !NO_MODULE_ENTRIES */
395
396#ifndef NO_MODULE_ENTRIES
397/* I wish these avoided the setjmp()/longjmp() crap in libpng instead
398 just allow you to change the error reporting. */
399static void png_error_callback (png_structp png_read_ptr,
400 png_const_charp error_msg);
401#endif
402
403#ifndef NO_MODULE_ENTRIES
404static void png_warning_callback (png_structp png_read_ptr,
405 png_const_charp warning_msg);
406#endif
407
408#ifndef NO_MODULE_ENTRIES
409/* Called at the start of the progressive load */
410static void png_info_callback (png_structp png_read_ptr,
411 png_infop png_info_ptr);
412#endif
413
414#ifndef NO_MODULE_ENTRIES
415/* Called for each row; note that you will get duplicate row numbers
416 for interlaced PNGs */
417static void png_row_callback (png_structp png_read_ptr,
418 png_bytep new_row,
419 png_uint_32 row_num,
420 int pass_num);
421#endif
422
423#ifndef NO_MODULE_ENTRIES
424/* Called after reading the entire image */
425static void png_end_callback (png_structp png_read_ptr,
426 png_infop png_info_ptr);
427#endif
428
429typedef struct _LoadContext LoadContext;
430
431struct _LoadContext {
432 png_structp png_read_ptr;
433 png_infop png_info_ptr;
434
435 CdkPixbufModuleSizeFunc size_func;
436 CdkPixbufModulePreparedFunc prepared_func;
437 CdkPixbufModuleUpdatedFunc updated_func;
438 gpointer notify_user_data;
439
440 CdkPixbuf* pixbuf;
441
442 /* row number of first row seen, or -1 if none yet seen */
443
444 gint first_row_seen_in_chunk;
445
446 /* pass number for the first row seen */
447
448 gint first_pass_seen_in_chunk;
449
450 /* row number of last row seen */
451 gint last_row_seen_in_chunk;
452
453 gint last_pass_seen_in_chunk;
454
455 /* highest row number seen */
456 gint max_row_seen_in_chunk;
457
458 guint fatal_error_occurred : 1;
459
460 GError **error;
461};
462
463#ifndef NO_MODULE_ENTRIES
464static gpointer
465cdk_pixbuf__png_image_begin_load (CdkPixbufModuleSizeFunc size_func,
466 CdkPixbufModulePreparedFunc prepared_func,
467 CdkPixbufModuleUpdatedFunc updated_func,
468 gpointer user_data,
469 GError **error)
470{
471 LoadContext* lc;
472
473 g_assert (size_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_19
= 0; if (size_func != ((void*)0)) _g_boolean_var_19 = 1; _g_boolean_var_19
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 473, ((const char*) (__func__)), "size_func != NULL"); } while
(0)
;
474 g_assert (prepared_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_20
= 0; if (prepared_func != ((void*)0)) _g_boolean_var_20 = 1;
_g_boolean_var_20; }), 1)) ; else g_assertion_message_expr (
"CdkPixbuf", "../cdk-pixbuf/io-png.c", 474, ((const char*) (__func__
)), "prepared_func != NULL"); } while (0)
;
475 g_assert (updated_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_21
= 0; if (updated_func != ((void*)0)) _g_boolean_var_21 = 1; _g_boolean_var_21
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 475, ((const char*) (__func__)), "updated_func != NULL"); }
while (0)
;
476
477 lc = g_new0(LoadContext, 1)(LoadContext *) (__extension__ ({ gsize __n = (gsize) (1); gsize
__s = sizeof (LoadContext); gpointer __p; if (__s == 1) __p =
g_malloc0 (__n); else if (__builtin_constant_p (__n) &&
(__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s
)) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s
); __p; }))
;
478
479 lc->fatal_error_occurred = FALSE(0);
480
481 lc->size_func = size_func;
482 lc->prepared_func = prepared_func;
483 lc->updated_func = updated_func;
484 lc->notify_user_data = user_data;
485
486 lc->first_row_seen_in_chunk = -1;
487 lc->last_row_seen_in_chunk = -1;
488 lc->first_pass_seen_in_chunk = -1;
489 lc->last_pass_seen_in_chunk = -1;
490 lc->max_row_seen_in_chunk = -1;
491 lc->error = error;
492
493 /* Create the main PNG context struct */
494
495#ifdef PNG_USER_MEM_SUPPORTED
496 lc->png_read_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING"1.6.58",
497 lc, /* error/warning callback data */
498 png_error_callback,
499 png_warning_callback,
500 NULL((void*)0),
501 png_malloc_callback,
502 png_free_callback);
503#else
504 lc->png_read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING"1.6.58",
505 lc, /* error/warning callback data */
506 png_error_callback,
507 png_warning_callback);
508#endif
509 if (lc->png_read_ptr == NULL((void*)0)) {
510 g_free(lc);
511
512 /* A failure here isn't supposed to call the error
513 * callback, but it doesn't hurt to be careful.
514 */
515 if (error && *error == NULL((void*)0)) {
516 g_set_error_literal (error,
517 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
518 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
519 _("Couldn’t allocate memory for loading PNG")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading PNG"
))
);
520 }
521
522 return NULL((void*)0);
523 }
524
525 /* Create the auxiliary context struct */
526
527 lc->png_info_ptr = png_create_info_struct(lc->png_read_ptr);
528
529 if (lc->png_info_ptr == NULL((void*)0)) {
530 png_destroy_read_struct(&lc->png_read_ptr, NULL((void*)0), NULL((void*)0));
531 g_free(lc);
532
533 /* A failure here isn't supposed to call the error
534 * callback, but it doesn't hurt to be careful.
535 */
536 if (error && *error == NULL((void*)0)) {
537 g_set_error_literal (error,
538 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
539 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
540 _("Couldn’t allocate memory for loading PNG")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading PNG"
))
);
541 }
542
543 return NULL((void*)0);
544 }
545
546 if (setjmp (png_jmpbuf(lc->png_read_ptr))_setjmp ((*png_set_longjmp_fn((lc->png_read_ptr), longjmp,
(sizeof (jmp_buf)))))
) {
547 png_destroy_read_struct(&lc->png_read_ptr, &lc->png_info_ptr, NULL((void*)0));
548 g_free(lc);
549 /* error callback should have set the error */
550 return NULL((void*)0);
551 }
552
553 png_set_progressive_read_fn(lc->png_read_ptr,
554 lc, /* callback data */
555 png_info_callback,
556 png_row_callback,
557 png_end_callback);
558
559
560 /* We don't want to keep modifying error after returning here,
561 * it may no longer be valid.
562 */
563 lc->error = NULL((void*)0);
564
565 return lc;
566}
567#endif /* !NO_MODULE_ENTRIES */
568
569#ifndef NO_MODULE_ENTRIES
570static gboolean
571cdk_pixbuf__png_image_stop_load (gpointer context, GError **error)
572{
573 LoadContext* lc = context;
574 gboolean retval = TRUE(!(0));
575
576 g_return_val_if_fail(lc != NULL, TRUE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_22
= 0; if (lc != ((void*)0)) _g_boolean_var_22 = 1; _g_boolean_var_22
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "lc != NULL"); return ((!(0))); } }
while (0)
;
577
578 /* FIXME this thing needs to report errors if
579 * we have unused image data
580 */
581
582 if (lc->pixbuf)
583 g_object_unref (lc->pixbuf);
584 else {
585 g_set_error_literal (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
586 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
587 _("Premature end-of-file encountered")((char *) g_dgettext ("cdk-pixbuf", "Premature end-of-file encountered"
))
);
588 retval = FALSE(0);
589 }
590
591 png_destroy_read_struct(&lc->png_read_ptr, &lc->png_info_ptr, NULL((void*)0));
592 g_free(lc);
593
594 return retval;
595}
596#endif /* !NO_MODULE_ENTRIES */
597
598#ifndef NO_MODULE_ENTRIES
599static gboolean
600cdk_pixbuf__png_image_load_increment(gpointer context,
601 const guchar *buf, guint size,
602 GError **error)
603{
604 LoadContext* lc = context;
605
606 g_return_val_if_fail(lc != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_23
= 0; if (lc != ((void*)0)) _g_boolean_var_23 = 1; _g_boolean_var_23
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "lc != NULL"); return ((0)); } } while
(0)
;
607
608 /* reset */
609 lc->first_row_seen_in_chunk = -1;
610 lc->last_row_seen_in_chunk = -1;
611 lc->first_pass_seen_in_chunk = -1;
612 lc->last_pass_seen_in_chunk = -1;
613 lc->max_row_seen_in_chunk = -1;
614 lc->error = error;
615
616 /* Invokes our callbacks as needed */
617 if (setjmp (png_jmpbuf(lc->png_read_ptr))_setjmp ((*png_set_longjmp_fn((lc->png_read_ptr), longjmp,
(sizeof (jmp_buf)))))
) {
618 lc->error = NULL((void*)0);
619 return FALSE(0);
620 } else {
621 png_process_data(lc->png_read_ptr, lc->png_info_ptr,
622 (guchar*) buf, size);
623 }
624
625 if (lc->fatal_error_occurred) {
626 lc->error = NULL((void*)0);
627 return FALSE(0);
628 } else {
629 if (lc->first_row_seen_in_chunk >= 0) {
630 gint width = cdk_pixbuf_get_width (lc->pixbuf);
631 /* We saw at least one row */
632 gint pass_diff = lc->last_pass_seen_in_chunk - lc->first_pass_seen_in_chunk;
633
634 g_assert(pass_diff >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_24
= 0; if (pass_diff >= 0) _g_boolean_var_24 = 1; _g_boolean_var_24
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 634, ((const char*) (__func__)), "pass_diff >= 0"); } while
(0)
;
635
636 if (pass_diff == 0) {
637 /* start and end row were in the same pass */
638 (lc->updated_func)(lc->pixbuf, 0,
639 lc->first_row_seen_in_chunk,
640 width,
641 (lc->last_row_seen_in_chunk -
642 lc->first_row_seen_in_chunk) + 1,
643 lc->notify_user_data);
644 } else if (pass_diff == 1) {
645 /* We have from the first row seen to
646 the end of the image (max row
647 seen), then from the top of the
648 image to the last row seen */
649 /* first row to end */
650 (lc->updated_func)(lc->pixbuf, 0,
651 lc->first_row_seen_in_chunk,
652 width,
653 (lc->max_row_seen_in_chunk -
654 lc->first_row_seen_in_chunk) + 1,
655 lc->notify_user_data);
656 /* top to last row */
657 (lc->updated_func)(lc->pixbuf,
658 0, 0,
659 width,
660 lc->last_row_seen_in_chunk + 1,
661 lc->notify_user_data);
662 } else {
663 /* We made at least one entire pass, so update the
664 whole image */
665 (lc->updated_func)(lc->pixbuf,
666 0, 0,
667 width,
668 lc->max_row_seen_in_chunk + 1,
669 lc->notify_user_data);
670 }
671 }
672
673 lc->error = NULL((void*)0);
674
675 return TRUE(!(0));
676 }
677}
678#endif /* !NO_MODULE_ENTRIES */
679
680#ifndef NO_MODULE_ENTRIES
681/* Called at the start of the progressive load, once we have image info */
682static void
683png_info_callback (png_structp png_read_ptr,
684 png_infop png_info_ptr)
685{
686 LoadContext* lc;
687 png_uint_32 width, height;
688 png_textp png_text_ptr;
689 int i, num_texts;
690 int color_type;
691 gboolean have_alpha = FALSE(0);
692 gchar *icc_profile_base64;
693 const gchar *icc_profile_title;
694 const gchar *icc_profile;
695 png_uint_32 icc_profile_size;
696 png_uint_32 x_resolution;
697 png_uint_32 y_resolution;
698 int unit_type;
699 gchar *density_str;
700 guint32 retval;
701 gint compression_type;
702
703 lc = png_get_progressive_ptr(png_read_ptr);
704
705 if (lc->fatal_error_occurred)
706 return;
707
708 if (!setup_png_transformations(lc->png_read_ptr,
709 lc->png_info_ptr,
710 lc->error,
711 &width, &height, &color_type)) {
712 lc->fatal_error_occurred = TRUE(!(0));
713 return;
714 }
715
716 /* If we have alpha, set a flag */
717 if (color_type & PNG_COLOR_MASK_ALPHA4)
718 have_alpha = TRUE(!(0));
719
720 {
721 gint w = width;
722 gint h = height;
723 (* lc->size_func) (&w, &h, lc->notify_user_data);
724
725 if (w == 0 || h == 0) {
726 lc->fatal_error_occurred = TRUE(!(0));
727 g_set_error_literal (lc->error,
728 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
729 CDK_PIXBUF_ERROR_FAILED,
730 _("Transformed PNG has zero width or height.")((char *) g_dgettext ("cdk-pixbuf", "Transformed PNG has zero width or height."
))
);
731 return;
732 }
733 }
734
735 lc->pixbuf = cdk_pixbuf_new (CDK_COLORSPACE_RGB, have_alpha, 8, width, height);
736
737 if (lc->pixbuf == NULL((void*)0)) {
738 /* Failed to allocate memory */
739 lc->fatal_error_occurred = TRUE(!(0));
740 g_set_error (lc->error,
741 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
742 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
743 _("Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage")((char *) g_dgettext ("cdk-pixbuf", "Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage"
))
,
744 (gulong) width, (gulong) height);
745 return;
746 }
747
748 cdk_pixbuf_fill (lc->pixbuf, DEFAULT_FILL_COLOR0x979899ff);
749
750 /* Extract text chunks and attach them as pixbuf options */
751
752 if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_texts)) {
753 for (i = 0; i < num_texts; i++) {
754 gchar *key, *value;
755
756 if (png_text_to_pixbuf_option (png_text_ptr[i],
757 &key, &value)) {
758 cdk_pixbuf_set_option (lc->pixbuf, key, value);
759 g_free (key);
760 g_free (value);
761 }
762 }
763 }
764
765#if defined(PNG_cHRM_SUPPORTED)
766 /* Extract embedded ICC profile */
767 retval = png_get_iCCP (png_read_ptr, png_info_ptr,
768 (png_charpp) &icc_profile_title, &compression_type,
769 (png_bytepp) &icc_profile, &icc_profile_size);
770 if (retval != 0) {
771 icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
772 cdk_pixbuf_set_option (lc->pixbuf, "icc-profile", icc_profile_base64);
773 g_free (icc_profile_base64);
774 }
775#endif
776
777#ifdef PNG_pHYs_SUPPORTED
778 retval = png_get_pHYs (png_read_ptr, png_info_ptr, &x_resolution, &y_resolution, &unit_type);
779 if (retval != 0 && unit_type == PNG_RESOLUTION_METER1) {
780 density_str = g_strdup_printf ("%d", DPM_TO_DPI (x_resolution)((int) round ((x_resolution) * 25.4 / 1000)));
781 cdk_pixbuf_set_option (lc->pixbuf, "x-dpi", density_str);
782 g_free (density_str);
783 density_str = g_strdup_printf ("%d", DPM_TO_DPI (y_resolution)((int) round ((y_resolution) * 25.4 / 1000)));
784 cdk_pixbuf_set_option (lc->pixbuf, "y-dpi", density_str);
785 g_free (density_str);
786 }
787#endif
788
789 /* Notify the client that we are ready to go */
790
791 (* lc->prepared_func) (lc->pixbuf, NULL((void*)0), lc->notify_user_data);
792
793 return;
794}
795#endif /* !NO_MODULE_ENTRIES */
796
797#ifndef NO_MODULE_ENTRIES
798/* Called for each row; note that you will get duplicate row numbers
799 for interlaced PNGs */
800static void
801png_row_callback (png_structp png_read_ptr,
802 png_bytep new_row,
803 png_uint_32 row_num,
804 int pass_num)
805{
806 LoadContext* lc;
807 guchar* old_row = NULL((void*)0);
808 gsize rowstride;
809
810 lc = png_get_progressive_ptr(png_read_ptr);
811
812 if (lc->fatal_error_occurred)
813 return;
814
815 if (row_num >= cdk_pixbuf_get_height (lc->pixbuf)) {
816 lc->fatal_error_occurred = TRUE(!(0));
817 g_set_error_literal (lc->error,
818 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
819 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
820 _("Fatal error reading PNG image file")((char *) g_dgettext ("cdk-pixbuf", "Fatal error reading PNG image file"
))
);
821 return;
822 }
823
824 if (lc->first_row_seen_in_chunk < 0) {
825 lc->first_row_seen_in_chunk = row_num;
826 lc->first_pass_seen_in_chunk = pass_num;
827 }
828
829 lc->max_row_seen_in_chunk = MAX(lc->max_row_seen_in_chunk, ((gint)row_num))(((lc->max_row_seen_in_chunk) > (((gint)row_num))) ? (lc
->max_row_seen_in_chunk) : (((gint)row_num)))
;
830 lc->last_row_seen_in_chunk = row_num;
831 lc->last_pass_seen_in_chunk = pass_num;
832
833 rowstride = cdk_pixbuf_get_rowstride (lc->pixbuf);
834 old_row = cdk_pixbuf_get_pixels (lc->pixbuf) + (row_num * rowstride);
835
836 png_progressive_combine_row(lc->png_read_ptr, old_row, new_row);
837}
838#endif /* !NO_MODULE_ENTRIES */
839
840#ifndef NO_MODULE_ENTRIES
841/* Called after reading the entire image */
842static void
843png_end_callback (png_structp png_read_ptr,
844 png_infop png_info_ptr)
845{
846 LoadContext* lc;
847
848 lc = png_get_progressive_ptr(png_read_ptr);
849
850 if (lc->fatal_error_occurred)
851 return;
852}
853#endif /* !NO_MODULE_ENTRIES */
854
855#ifndef NO_MODULE_ENTRIES
856static void
857png_error_callback(png_structp png_read_ptr,
858 png_const_charp error_msg)
859{
860 LoadContext* lc;
861
862 lc = png_get_error_ptr(png_read_ptr);
863
864 lc->fatal_error_occurred = TRUE(!(0));
865
866 /* I don't trust libpng to call the error callback only once,
867 * so check for already-set error
868 */
869 if (lc->error && *lc->error == NULL((void*)0)) {
870 g_set_error (lc->error,
871 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
872 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
873 _("Fatal error reading PNG image file: %s")((char *) g_dgettext ("cdk-pixbuf", "Fatal error reading PNG image file: %s"
))
,
874 error_msg);
875 }
876
877 longjmp (png_jmpbuf(png_read_ptr)(*png_set_longjmp_fn((png_read_ptr), longjmp, (sizeof (jmp_buf
))))
, 1);
878}
879#endif /* !NO_MODULE_ENTRIES */
880
881#ifndef NO_MODULE_ENTRIES
882static void
883png_warning_callback (png_structp png_read_ptr,
884 png_const_charp warning_msg)
885{
886 /* Don't print anything; we should not be dumping junk to
887 * stderr, since that may be bad for some apps. If it's
888 * important enough to display, we need to add a GError
889 * **warning return location wherever we have an error return
890 * location.
891 */
892}
893#endif /* !NO_MODULE_ENTRIES */
894
895/* Save */
896
897typedef struct {
898 CdkPixbufSaveFunc save_func;
899 gpointer user_data;
900 GError **error;
901} SaveToFunctionIoPtr;
902
903static void
904png_save_to_callback_write_func (png_structp png_ptr,
905 png_bytep data,
906 png_size_t length)
907{
908 SaveToFunctionIoPtr *ioptr = png_get_io_ptr (png_ptr);
909
910 if (!ioptr->save_func ((gchar *)data, length, ioptr->error, ioptr->user_data)) {
911 /* If save_func has already set an error, which it
912 should have done, this won't overwrite it. */
913 png_error (png_ptr, "write function failed");
914 }
915}
916
917static void
918png_save_to_callback_flush_func (png_structp png_ptr)
919{
920 ;
921}
922
923static gboolean
924real_save_png (CdkPixbuf *pixbuf,
925 int n_keys,
926 gchar **keys,
927 gchar **values,
928 GError **error,
929 gboolean to_callback,
930 FILE *f,
931 CdkPixbufSaveFunc save_func,
932 gpointer user_data)
933{
934 png_structp png_ptr = NULL((void*)0);
935 png_infop info_ptr;
936 guchar *ptr;
937 guchar *pixels;
938 int y;
939 png_bytep row_ptr;
940 png_color_8 sig_bit;
941 int w, h, rowstride;
942 int has_alpha;
943 int bpc;
944 int compression = -1;
945 int x_density = 0;
946 int y_density = 0;
947 gboolean success = TRUE(!(0));
948 guchar *icc_profile = NULL((void*)0);
949 gsize icc_profile_size = 0;
950 SaveToFunctionIoPtr to_callback_ioptr;
951 int num_keys = 0;
952 png_textp text_ptr = NULL((void*)0);
953 GArray *text_data = NULL((void*)0);
954
955 text_data = g_array_sized_new (FALSE(0), TRUE(!(0)), sizeof (png_text), n_keys);
956
957 for (int i = 0; i < n_keys; i++) {
958 const char *key = keys[i];
959 const char *value = values[i];
960
961 if (strncmp (key, "tEXt::", 6) == 0) {
962 const char *unprefixed_key = key + 6;
963 int len = strlen (unprefixed_key);
964 png_text text;
965
966 if (len < 1 || len > 79) {
967 /* Translators notice: '%s' is the name of the
968 * PNG text key
969 */
970 g_set_error (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
971 CDK_PIXBUF_ERROR_BAD_OPTION,
972 _("Invalid key “%s”. Keys for PNG text chunks must have at least 1 and at most 79 characters.")((char *) g_dgettext ("cdk-pixbuf", "Invalid key “%s”. Keys for PNG text chunks must have at least 1 and at most 79 characters."
))
,
973 unprefixed_key);
974 success = FALSE(0);
975 goto cleanup;
976 }
977
978 for (int i = 0; i < len; i++) {
979 if ((guchar) unprefixed_key[i] > 127) {
980 /* Translators notice: '%s' is the name of
981 * the PNG text key
982 */
983 g_set_error (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
984 CDK_PIXBUF_ERROR_BAD_OPTION,
985 _("Invalid key “%s”. Keys for PNG text chunks must be ASCII characters.")((char *) g_dgettext ("cdk-pixbuf", "Invalid key “%s”. Keys for PNG text chunks must be ASCII characters."
))
,
986 unprefixed_key);
987 success = FALSE(0);
988 goto cleanup;
989 }
990 }
991
992 text.compression = PNG_TEXT_COMPRESSION_NONE-1;
993 text.key = unprefixed_key;
994 text.text = g_convert (value, -1,
995 "ISO-8859-1", "UTF-8",
996 NULL((void*)0),
997 &text.text_length,
998 NULL((void*)0));
999
1000#ifdef PNG_iTXt_SUPPORTED
1001 if (text.text == NULL((void*)0)) {
1002 text.compression = PNG_ITXT_COMPRESSION_NONE1;
1003 text.text = g_strdup (value)g_strdup_inline (value);
1004 text.text_length = 0;
1005 text.itxt_length = strlen (value);
1006 text.lang = NULL((void*)0);
1007 text.lang_key = NULL((void*)0);
1008 }
1009#endif
1010
1011 if (text.text == NULL((void*)0)) {
1012 g_set_error (error,
1013 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1014 CDK_PIXBUF_ERROR_BAD_OPTION,
1015 _("Value for PNG text chunk '%s' cannot be converted to ISO-8859-1 encoding.")((char *) g_dgettext ("cdk-pixbuf", "Value for PNG text chunk '%s' cannot be converted to ISO-8859-1 encoding."
))
, unprefixed_key);
1016 success = FALSE(0);
1017 goto cleanup;
1018 }
1019
1020 g_array_append_val (text_data, text)g_array_append_vals (text_data, &(text), 1);
1021 } else if (strcmp (key, "icc-profile") == 0) {
1022 icc_profile = g_base64_decode (value, &icc_profile_size);
1023
1024 if (icc_profile_size < 127) {
1025 g_set_error (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1026 CDK_PIXBUF_ERROR_BAD_OPTION,
1027 _("Color profile has invalid length %d")((char *) g_dgettext ("cdk-pixbuf", "Color profile has invalid length %d"
))
,
1028 (int) icc_profile_size);
1029 success = FALSE(0);
1030 goto cleanup;
1031 }
1032 } else if (strcmp (key, "compression") == 0) {
1033 char *endptr = NULL((void*)0);
1034
1035 compression = strtol (value, &endptr, 10);
1036 if (endptr == value || (compression < 0 || compression > 9)) {
1037 g_set_error (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1038 CDK_PIXBUF_ERROR_BAD_OPTION,
1039 _("PNG compression level must be a value between 0 and 9; value “%s” is invalid")((char *) g_dgettext ("cdk-pixbuf", "PNG compression level must be a value between 0 and 9; value “%s” is invalid"
))
,
1040 value);
1041 success = FALSE(0);
1042 goto cleanup;
1043 }
1044 } else if (strcmp (key, "x-dpi") == 0 || strcmp (key, "y-dpi") == 0) {
1045 gboolean is_horizontal = strcmp (key, "x-dpi") == 0;
1046 char *endptr = NULL((void*)0);
1047
1048 int dpi = strtol (value, &endptr, 10);
1049
1050 if (endptr == value || dpi <= 0) {
1051 g_set_error (error, CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1052 CDK_PIXBUF_ERROR_BAD_OPTION,
1053 _("PNG %s must be greater than zero; value “%s” is not allowed")((char *) g_dgettext ("cdk-pixbuf", "PNG %s must be greater than zero; value “%s” is not allowed"
))
,
1054 is_horizontal ? "x-dpi" : "y-dpi",
1055 value);
1056 success = FALSE(0);
1057 goto cleanup;
1058 }
1059
1060 if (is_horizontal) {
1061 x_density = dpi;
1062 } else {
1063 y_density = dpi;
1064 }
1065 } else {
1066 g_warning ("Unrecognized parameter “%s” passed to the PNG saver", key);
1067 }
1068 }
1069
1070 bpc = cdk_pixbuf_get_bits_per_sample (pixbuf);
1071 w = cdk_pixbuf_get_width (pixbuf);
1072 h = cdk_pixbuf_get_height (pixbuf);
1073 rowstride = cdk_pixbuf_get_rowstride (pixbuf);
1074 has_alpha = cdk_pixbuf_get_has_alpha (pixbuf);
1075 pixels = cdk_pixbuf_get_pixels (pixbuf);
1076
1077 if (text_data->len > 0) {
1078 num_keys = text_data->len;
1079 text_ptr = (png_textp) g_array_free (text_data, FALSE(0));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
1080 text_data = NULL((void*)0);
1081 } else {
1082 g_clear_pointer (&text_data, g_array_unref)do { _Static_assert (sizeof *(&text_data) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ ((&text_data
)) _pp = (&text_data); __typeof__ (*(&text_data)) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_array_unref) (_ptr);
} while (0)
;
1083 num_keys = 0;
1084 text_ptr = NULL((void*)0);
1085 }
1086
1087 /* Guaranteed by the caller. */
1088 g_assert (w >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_25
= 0; if (w >= 0) _g_boolean_var_25 = 1; _g_boolean_var_25
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 1088, ((const char*) (__func__)), "w >= 0"); } while (0)
;
1089 g_assert (h >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_26
= 0; if (h >= 0) _g_boolean_var_26 = 1; _g_boolean_var_26
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 1089, ((const char*) (__func__)), "h >= 0"); } while (0)
;
1090 g_assert (rowstride >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_27
= 0; if (rowstride >= 0) _g_boolean_var_27 = 1; _g_boolean_var_27
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-png.c"
, 1090, ((const char*) (__func__)), "rowstride >= 0"); } while
(0)
;
1091
1092 png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING"1.6.58",
1093 error,
1094 png_simple_error_callback,
1095 png_simple_warning_callback);
1096 if (png_ptr == NULL((void*)0)) {
1097 success = FALSE(0);
1098 goto cleanup;
1099 }
1100
1101 info_ptr = png_create_info_struct (png_ptr);
1102 if (info_ptr == NULL((void*)0)) {
1103 success = FALSE(0);
1104 goto cleanup;
1105 }
1106
1107 if (setjmp (png_jmpbuf (png_ptr))_setjmp ((*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf
)))))
) {
1108 success = FALSE(0);
1109 goto cleanup;
1110 }
1111
1112 if (num_keys > 0) {
1113 png_set_text (png_ptr, info_ptr, text_ptr, num_keys);
1114 }
1115
1116 if (to_callback) {
1117 to_callback_ioptr.save_func = save_func;
1118 to_callback_ioptr.user_data = user_data;
1119 to_callback_ioptr.error = error;
1120 png_set_write_fn (png_ptr, &to_callback_ioptr,
1121 png_save_to_callback_write_func,
1122 png_save_to_callback_flush_func);
1123 } else {
1124 png_init_io (png_ptr, f);
1125 }
1126
1127 if (compression >= 0) {
1128 png_set_compression_level (png_ptr, compression);
1129 }
1130
1131#ifdef PNG_pHYs_SUPPORTED
1132 if (x_density > 0 && y_density > 0) {
1133 png_set_pHYs (png_ptr, info_ptr,
1134 DPI_TO_DPM (x_density)((int) round ((x_density) * 1000 / 25.4)),
1135 DPI_TO_DPM (y_density)((int) round ((y_density) * 1000 / 25.4)),
1136 PNG_RESOLUTION_METER1);
1137 }
1138#endif
1139
1140#if defined(PNG_iCCP_SUPPORTED)
1141 /* the proper ICC profile title is encoded in the profile */
1142 if (icc_profile != NULL((void*)0)) {
1143 png_set_iCCP (png_ptr, info_ptr,
1144 "ICC profile",
1145 PNG_COMPRESSION_TYPE_BASE0,
1146 (png_bytep) icc_profile,
1147 icc_profile_size);
1148 }
1149#endif
1150
1151 if (has_alpha) {
1152 png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
1153 PNG_COLOR_TYPE_RGB_ALPHA(2 | 4),
1154 PNG_INTERLACE_NONE0,
1155 PNG_COMPRESSION_TYPE_BASE0,
1156 PNG_FILTER_TYPE_BASE0);
1157 } else {
1158 png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
1159 PNG_COLOR_TYPE_RGB(2),
1160 PNG_INTERLACE_NONE0,
1161 PNG_COMPRESSION_TYPE_BASE0,
1162 PNG_FILTER_TYPE_BASE0);
1163 }
1164
1165 /* Note bpc is always 8 */
1166 sig_bit.red = bpc;
1167 sig_bit.green = bpc;
1168 sig_bit.blue = bpc;
1169 sig_bit.alpha = bpc;
1170 png_set_sBIT (png_ptr, info_ptr, &sig_bit);
1171 png_write_info (png_ptr, info_ptr);
1172 png_set_packing (png_ptr);
1173
1174 for (y = 0, ptr = pixels; y < h; y++, ptr += rowstride) {
1175 row_ptr = (png_bytep)ptr;
1176 png_write_rows (png_ptr, &row_ptr, 1);
1177 }
1178
1179 png_write_end (png_ptr, info_ptr);
1180
1181 for (int i = 0; i < num_keys; i++) {
1182 g_free (text_ptr[i].text);
1183 }
1184
1185 g_free (text_ptr);
1186
1187cleanup:
1188 if (png_ptr != NULL((void*)0)) {
1189 png_destroy_write_struct (&png_ptr, &info_ptr);
1190 }
1191
1192 if (text_data != NULL((void*)0)) {
1193 for (guint i = 0; i < text_data->len; i++) {
1194 png_textp text = &g_array_index (text_data, png_text, i)(((png_text*) (void *) (text_data)->data) [(i)]);
1195
1196 g_free (text->text);
1197 }
1198
1199 g_array_unref (text_data);
1200 }
1201
1202 g_free (icc_profile);
1203
1204 return success;
1205}
1206
1207static gboolean
1208cdk_pixbuf__png_image_save (FILE *f,
1209 CdkPixbuf *pixbuf,
1210 gchar **keys,
1211 gchar **values,
1212 GError **error)
1213{
1214 int n_keys = keys != NULL((void*)0) ? g_strv_length (keys) : 0;
1215
1216 return real_save_png (pixbuf, n_keys, keys, values, error,
1217 FALSE(0), f, NULL((void*)0), NULL((void*)0));
1218}
1219
1220static gboolean
1221cdk_pixbuf__png_image_save_to_callback (CdkPixbufSaveFunc save_func,
1222 gpointer user_data,
1223 CdkPixbuf *pixbuf,
1224 gchar **keys,
1225 gchar **values,
1226 GError **error)
1227{
1228 int n_keys = keys != NULL((void*)0) ? g_strv_length (keys) : 0;
1229
1230 return real_save_png (pixbuf, n_keys, keys, values, error,
1231 TRUE(!(0)), NULL((void*)0), save_func, user_data);
1232}
1233
1234static gboolean
1235cdk_pixbuf__png_is_save_option_supported (const gchar *option_key)
1236{
1237 if (g_strcmp0 (option_key, "compression") == 0 ||
1238 g_strcmp0 (option_key, "icc-profile") == 0 ||
1239 g_strcmp0 (option_key, "x-dpi") == 0 ||
1240 g_strcmp0 (option_key, "y-dpi") == 0 ||
1241 strncmp (option_key, "tEXt::", 6) == 0)
1242 return TRUE(!(0));
1243
1244 return FALSE(0);
1245}
1246
1247#ifndef NO_MODULE_ENTRIES
1248
1249#ifndef INCLUDE_png1
1250#define MODULE_ENTRY(function)void _cdk_pixbuf__png_function G_MODULE_EXPORT__attribute__((visibility("default"))) void function
1251#else
1252#define MODULE_ENTRY(function)void _cdk_pixbuf__png_function void _cdk_pixbuf__png_ ## function
1253#endif
1254
1255MODULE_ENTRY (fill_vtable)void _cdk_pixbuf__png_fill_vtable (CdkPixbufModule *module)
1256{
1257 module->load = cdk_pixbuf__png_image_load;
1258 module->begin_load = cdk_pixbuf__png_image_begin_load;
1259 module->stop_load = cdk_pixbuf__png_image_stop_load;
1260 module->load_increment = cdk_pixbuf__png_image_load_increment;
1261 module->save = cdk_pixbuf__png_image_save;
1262 module->save_to_callback = cdk_pixbuf__png_image_save_to_callback;
1263 module->is_save_option_supported = cdk_pixbuf__png_is_save_option_supported;
1264}
1265
1266MODULE_ENTRY (fill_info)void _cdk_pixbuf__png_fill_info (CdkPixbufFormat *info)
1267{
1268 static const CdkPixbufModulePattern signature[] = {
1269 { "\x89PNG\r\n\x1a\x0a", NULL((void*)0), 100 },
1270 { NULL((void*)0), NULL((void*)0), 0 }
1271 };
1272 static const gchar *mime_types[] = {
1273 "image/png",
1274 NULL((void*)0)
1275 };
1276 static const gchar *extensions[] = {
1277 "png",
1278 NULL((void*)0)
1279 };
1280
1281 info->name = "png";
1282 info->signature = (CdkPixbufModulePattern *) signature;
1283 info->description = NC_("image format", "PNG")("PNG");
1284 info->mime_types = (gchar **) mime_types;
1285 info->extensions = (gchar **) extensions;
1286 info->flags = CDK_PIXBUF_FORMAT_WRITABLE | CDK_PIXBUF_FORMAT_THREADSAFE;
1287 info->license = "LGPL";
1288}
1289
1290#endif