Bug Summary

File:_build/../cdk-pixbuf/io-jpeg.c
Warning:line 382, column 2
Null pointer passed to 1st parameter expecting 'nonnull'

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-jpeg.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-jpeg.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_jpeg -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-083413-8532-1 -x c ../cdk-pixbuf/io-jpeg.c
1/* -*- mode: C; c-file-style: "linux" -*- */
2/* CdkPixbuf library - JPEG image loader
3 *
4 * Copyright (C) 1999 Michael Zucchi
5 * Copyright (C) 1999 The Free Software Foundation
6 *
7 * Progressive loading code Copyright (C) 1999 Red Hat, Inc.
8 *
9 * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
10 * Federico Mena-Quintero <federico@gimp.org>
11 * Michael Fulbright <drmike@redhat.com>
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 */
26
27
28#include "config.h"
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <setjmp.h>
33#include <jpeglib.h>
34#include <jerror.h>
35#include <math.h>
36#include <glib/gi18n-lib.h>
37#include "cdk-pixbuf-io.h"
38#include "fallback-c89.c"
39
40#ifndef HAVE_SIGSETJMP
41#define sigjmp_buf jmp_buf
42#define sigsetjmp(jb, x)__sigsetjmp (jb, x) setjmp(jb)_setjmp (jb)
43#define siglongjmp longjmp
44#endif
45
46
47/* Helper macros to convert between density units */
48#define DPCM_TO_DPI(value)((int) round ((value) * 2.54)) ((int) round ((value) * 2.54))
49
50/* we are a "source manager" as far as libjpeg is concerned */
51#define JPEG_PROG_BUF_SIZE65536 65536
52
53typedef struct {
54 struct jpeg_source_mgr pub; /* public fields */
55
56 JOCTET buffer[JPEG_PROG_BUF_SIZE65536]; /* start of buffer */
57 long skip_next; /* number of bytes to skip next read */
58
59} my_source_mgr;
60
61typedef my_source_mgr * my_src_ptr;
62
63/* error handler data */
64struct error_handler_data {
65 struct jpeg_error_mgr pub;
66 sigjmp_buf setjmp_buffer;
67 GError **error;
68};
69
70/* progressive loader context */
71typedef struct {
72 CdkPixbufModuleSizeFunc size_func;
73 CdkPixbufModuleUpdatedFunc updated_func;
74 CdkPixbufModulePreparedFunc prepared_func;
75 gpointer user_data;
76
77 CdkPixbuf *pixbuf;
78 guchar *dptr; /* current position in pixbuf */
79
80 gboolean did_prescan; /* are we in image data yet? */
81 gboolean got_header; /* have we loaded jpeg header? */
82 gboolean src_initialized;/* TRUE when jpeg lib initialized */
83 gboolean in_output; /* did we get suspended in an output pass? */
84 struct jpeg_decompress_struct cinfo;
85 struct error_handler_data jerr;
86} JpegProgContext;
87
88/* EXIF context */
89typedef struct {
90 gint orientation;
91 gchar *icc_profile;
92 gsize icc_profile_size;
93 gsize icc_profile_size_allocated;
94} JpegExifContext;
95
96#ifndef NO_MODULE_ENTRIES
97static CdkPixbuf *cdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
98static gpointer cdk_pixbuf__jpeg_image_begin_load (CdkPixbufModuleSizeFunc func0,
99 CdkPixbufModulePreparedFunc func1,
100 CdkPixbufModuleUpdatedFunc func2,
101 gpointer user_data,
102 GError **error);
103static gboolean cdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
104static gboolean cdk_pixbuf__jpeg_image_load_increment(gpointer context,
105 const guchar *buf, guint size,
106 GError **error);
107static gboolean cdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
108 GError **error);
109#endif
110
111static void
112fatal_error_handler (j_common_ptr cinfo)
113{
114 struct error_handler_data *errmgr;
115 char buffer[JMSG_LENGTH_MAX200];
116
117 errmgr = (struct error_handler_data *) cinfo->err;
118
119 /* Create the message */
120 (* cinfo->err->format_message) (cinfo, buffer);
121
122 /* broken check for *error == NULL for robustness against
123 * crappy JPEG library
124 */
125 if (errmgr->error && *errmgr->error == NULL((void*)0)) {
126 g_set_error (errmgr->error,
127 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
128 cinfo->err->msg_code == JERR_OUT_OF_MEMORY
129 ? CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY
130 : CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
131 _("Error interpreting JPEG image file (%s)")((char *) g_dgettext ("cdk-pixbuf", "Error interpreting JPEG image file (%s)"
))
,
132 buffer);
133 }
134
135 siglongjmp (errmgr->setjmp_buffer, 1);
136
137 g_assert_not_reached ()do { g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 137, ((const char*) (__func__)), ((void*)0)); } while (0)
;
138}
139
140static void
141output_message_handler (j_common_ptr cinfo)
142{
143 /* This method keeps libjpeg from dumping crap to stderr */
144
145 /* do nothing */
146}
147
148#ifndef NO_MODULE_ENTRIES
149/* explode gray image data from jpeg library into rgb components in pixbuf */
150static void
151explode_gray_into_buf (struct jpeg_decompress_struct *cinfo,
152 guchar **lines)
153{
154 gint i, j;
155 guint w;
156
157 g_return_if_fail (cinfo != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_26
= 0; if (cinfo != ((void*)0)) _g_boolean_var_26 = 1; _g_boolean_var_26
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "cinfo != NULL"); return; } } while
(0)
;
158 g_return_if_fail (cinfo->output_components == 1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_27
= 0; if (cinfo->output_components == 1) _g_boolean_var_27
= 1; _g_boolean_var_27; }), 1))) { } else { g_return_if_fail_warning
("CdkPixbuf", ((const char*) (__func__)), "cinfo->output_components == 1"
); return; } } while (0)
;
159 g_return_if_fail (cinfo->out_color_space == JCS_GRAYSCALE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_28
= 0; if (cinfo->out_color_space == JCS_GRAYSCALE) _g_boolean_var_28
= 1; _g_boolean_var_28; }), 1))) { } else { g_return_if_fail_warning
("CdkPixbuf", ((const char*) (__func__)), "cinfo->out_color_space == JCS_GRAYSCALE"
); return; } } while (0)
;
160
161 /* Expand grey->colour. Expand from the end of the
162 * memory down, so we can use the same buffer.
163 */
164 w = cinfo->output_width;
165 for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
166 guchar *from, *to;
167
168 from = lines[i] + w - 1;
169 to = lines[i] + (w - 1) * 3;
170 for (j = w - 1; j >= 0; j--) {
171 to[0] = from[0];
172 to[1] = from[0];
173 to[2] = from[0];
174 to -= 3;
175 from--;
176 }
177 }
178}
179
180
181static void
182convert_cmyk_to_rgb (struct jpeg_decompress_struct *cinfo,
183 guchar **lines)
184{
185 gint i, j;
186
187 g_return_if_fail (cinfo != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_29
= 0; if (cinfo != ((void*)0)) _g_boolean_var_29 = 1; _g_boolean_var_29
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "cinfo != NULL"); return; } } while
(0)
;
188 g_return_if_fail (cinfo->output_components == 4)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_30
= 0; if (cinfo->output_components == 4) _g_boolean_var_30
= 1; _g_boolean_var_30; }), 1))) { } else { g_return_if_fail_warning
("CdkPixbuf", ((const char*) (__func__)), "cinfo->output_components == 4"
); return; } } while (0)
;
189 g_return_if_fail (cinfo->out_color_space == JCS_CMYK)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_31
= 0; if (cinfo->out_color_space == JCS_CMYK) _g_boolean_var_31
= 1; _g_boolean_var_31; }), 1))) { } else { g_return_if_fail_warning
("CdkPixbuf", ((const char*) (__func__)), "cinfo->out_color_space == JCS_CMYK"
); return; } } while (0)
;
190
191 for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
192 guchar *p;
193
194 p = lines[i];
195 for (j = 0; j < cinfo->output_width; j++) {
196 int c, m, y, k;
197 c = p[0];
198 m = p[1];
199 y = p[2];
200 k = p[3];
201
202 /* We now assume that all CMYK JPEG files
203 * use inverted CMYK, as Photoshop does
204 * See https://bugzilla.gnome.org/show_bug.cgi?id=618096 */
205 p[0] = k*c / 255;
206 p[1] = k*m / 255;
207 p[2] = k*y / 255;
208 p[3] = 255;
209 p += 4;
210 }
211 }
212}
213
214typedef struct {
215 struct jpeg_source_mgr pub; /* public fields */
216
217 FILE * infile; /* source stream */
218 JOCTET * buffer; /* start of buffer */
219 boolean start_of_file; /* have we gotten any data yet? */
220} stdio_source_mgr;
221
222typedef stdio_source_mgr * stdio_src_ptr;
223
224static void
225stdio_init_source (j_decompress_ptr cinfo)
226{
227 stdio_src_ptr src = (stdio_src_ptr)cinfo->src;
228 src->start_of_file = FALSE0;
229}
230
231static boolean
232stdio_fill_input_buffer (j_decompress_ptr cinfo)
233{
234 stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
235 size_t nbytes;
236
237 nbytes = fread (src->buffer, 1, JPEG_PROG_BUF_SIZE65536, src->infile);
238
239 if (nbytes <= 0) {
240#if 0
241 if (src->start_of_file) /* Treat empty input file as fatal error */
242 ERREXIT(cinfo, JERR_INPUT_EMPTY)((cinfo)->err->msg_code = (JERR_INPUT_EMPTY), (*(cinfo)
->err->error_exit) ((j_common_ptr)(cinfo)))
;
243 WARNMS(cinfo, JWRN_JPEG_EOF)((cinfo)->err->msg_code = (JWRN_JPEG_EOF), (*(cinfo)->
err->emit_message) ((j_common_ptr)(cinfo), -1))
;
244#endif
245 /* Insert a fake EOI marker */
246 src->buffer[0] = (JOCTET) 0xFF;
247 src->buffer[1] = (JOCTET) JPEG_EOI0xD9;
248 nbytes = 2;
249 }
250
251 src->pub.next_input_byte = src->buffer;
252 src->pub.bytes_in_buffer = nbytes;
253 src->start_of_file = FALSE0;
254
255 return TRUE1;
256}
257
258static void
259stdio_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
260{
261 stdio_src_ptr src = (stdio_src_ptr) cinfo->src;
262
263 if (num_bytes > 0) {
264 while (num_bytes > (long) src->pub.bytes_in_buffer) {
265 num_bytes -= (long) src->pub.bytes_in_buffer;
266 (void)stdio_fill_input_buffer(cinfo);
267 }
268 src->pub.next_input_byte += (size_t) num_bytes;
269 src->pub.bytes_in_buffer -= (size_t) num_bytes;
270 }
271}
272
273static void
274stdio_term_source (j_decompress_ptr cinfo)
275{
276}
277
278static gchar *
279colorspace_name (const J_COLOR_SPACE jpeg_color_space)
280{
281 switch (jpeg_color_space) {
282 case JCS_UNKNOWN: return "UNKNOWN";
283 case JCS_GRAYSCALE: return "GRAYSCALE";
284 case JCS_RGB: return "RGB";
285 case JCS_YCbCr: return "YCbCr";
286 case JCS_CMYK: return "CMYK";
287 case JCS_YCCK: return "YCCK";
288 default: return "invalid";
289 }
290}
291
292#define DE_ENDIAN16(val)endian == 4321 ? (((((guint16) ( (guint16) ((guint16) (val) >>
8) | (guint16) ((guint16) (val) << 8)))))) : (((guint16
) (val)))
endian == G_BIG_ENDIAN4321 ? GUINT16_FROM_BE(val)(((((guint16) ( (guint16) ((guint16) (val) >> 8) | (guint16
) ((guint16) (val) << 8))))))
: GUINT16_FROM_LE(val)(((guint16) (val)))
293#define DE_ENDIAN32(val)endian == 4321 ? ((((__extension__ ({ guint32 __v, __x = ((guint32
) (val)); if (__builtin_constant_p (__x)) __v = ((guint32) ( (
((guint32) (__x) & (guint32) 0x000000ffU) << 24) | (
((guint32) (__x) & (guint32) 0x0000ff00U) << 8) | (
((guint32) (__x) & (guint32) 0x00ff0000U) >> 8) | (
((guint32) (__x) & (guint32) 0xff000000U) >> 24)));
else __asm__ ("bswapl %0" : "=r" (__v) : "0" (__x)); __v; })
)))) : (((guint32) (val)))
endian == G_BIG_ENDIAN4321 ? GUINT32_FROM_BE(val)((((__extension__ ({ guint32 __v, __x = ((guint32) (val)); if
(__builtin_constant_p (__x)) __v = ((guint32) ( (((guint32) (
__x) & (guint32) 0x000000ffU) << 24) | (((guint32) (
__x) & (guint32) 0x0000ff00U) << 8) | (((guint32) (
__x) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (
__x) & (guint32) 0xff000000U) >> 24))); else __asm__
("bswapl %0" : "=r" (__v) : "0" (__x)); __v; })))))
: GUINT32_FROM_LE(val)(((guint32) (val)))
294
295#define ENDIAN16_IT(val)endian == 4321 ? ((((guint16) ( (guint16) ((guint16) (val) >>
8) | (guint16) ((guint16) (val) << 8))))) : ((guint16)
(val))
endian == G_BIG_ENDIAN4321 ? GUINT16_TO_BE(val)((((guint16) ( (guint16) ((guint16) (val) >> 8) | (guint16
) ((guint16) (val) << 8)))))
: GUINT16_TO_LE(val)((guint16) (val))
296#define ENDIAN32_IT(val)endian == 4321 ? (((__extension__ ({ guint32 __v, __x = ((guint32
) (val)); if (__builtin_constant_p (__x)) __v = ((guint32) ( (
((guint32) (__x) & (guint32) 0x000000ffU) << 24) | (
((guint32) (__x) & (guint32) 0x0000ff00U) << 8) | (
((guint32) (__x) & (guint32) 0x00ff0000U) >> 8) | (
((guint32) (__x) & (guint32) 0xff000000U) >> 24)));
else __asm__ ("bswapl %0" : "=r" (__v) : "0" (__x)); __v; })
))) : ((guint32) (val))
endian == G_BIG_ENDIAN4321 ? GUINT32_TO_BE(val)(((__extension__ ({ guint32 __v, __x = ((guint32) (val)); if (
__builtin_constant_p (__x)) __v = ((guint32) ( (((guint32) (__x
) & (guint32) 0x000000ffU) << 24) | (((guint32) (__x
) & (guint32) 0x0000ff00U) << 8) | (((guint32) (__x
) & (guint32) 0x00ff0000U) >> 8) | (((guint32) (__x
) & (guint32) 0xff000000U) >> 24))); else __asm__ (
"bswapl %0" : "=r" (__v) : "0" (__x)); __v; }))))
: GUINT32_TO_LE(val)((guint32) (val))
297
298static unsigned short de_get16(void *ptr, guint endian)
299{
300 unsigned short val;
301
302 memcpy(&val, ptr, sizeof(val));
303 val = DE_ENDIAN16(val)endian == 4321 ? (((((guint16) ( (guint16) ((guint16) (val) >>
8) | (guint16) ((guint16) (val) << 8)))))) : (((guint16
) (val)))
;
304
305 return val;
306}
307
308static unsigned int de_get32(void *ptr, guint endian)
309{
310 unsigned int val;
311
312 memcpy(&val, ptr, sizeof(val));
313 val = DE_ENDIAN32(val)endian == 4321 ? ((((__extension__ ({ guint32 __v, __x = ((guint32
) (val)); if (__builtin_constant_p (__x)) __v = ((guint32) ( (
((guint32) (__x) & (guint32) 0x000000ffU) << 24) | (
((guint32) (__x) & (guint32) 0x0000ff00U) << 8) | (
((guint32) (__x) & (guint32) 0x00ff0000U) >> 8) | (
((guint32) (__x) & (guint32) 0xff000000U) >> 24)));
else __asm__ ("bswapl %0" : "=r" (__v) : "0" (__x)); __v; })
)))) : (((guint32) (val)))
;
314
315 return val;
316}
317
318/* application specific data segment */
319static gboolean
320jpeg_parse_exif_app2_segment (JpegExifContext *context, jpeg_saved_marker_ptr marker)
321{
322 guint ret = FALSE0;
323 guint sequence_number;
324 guint number_of_chunks;
325 guint chunk_size;
326 guint offset;
327
328 /* do we have enough data? */
329 if (marker->data_length < 16)
31
Assuming field 'data_length' is >= 16
32
Taking false branch
56
Assuming field 'data_length' is >= 16
57
Taking false branch
330 goto out;
331
332 /* unique identification string */
333 if (memcmp (marker->data, "ICC_PROFILE\0", 12) != 0)
33
Assuming the condition is false
34
Taking false branch
58
Assuming the condition is false
59
Taking false branch
334 goto out;
335
336 /* get data about this segment */
337 sequence_number = marker->data[12];
338 number_of_chunks = marker->data[13];
339
340 /* this is invalid, the base offset is 1 */
341 if (sequence_number == 0)
35
Assuming 'sequence_number' is not equal to 0
36
Taking false branch
60
Assuming 'sequence_number' is not equal to 0
61
Taking false branch
342 goto out;
343
344 /* this is invalid, the base offset is 1 */
345 if (sequence_number > number_of_chunks)
37
Assuming 'sequence_number' is <= 'number_of_chunks'
38
Taking false branch
62
Assuming 'sequence_number' is <= 'number_of_chunks'
63
Taking false branch
346 goto out;
347
348 /* size includes the id (12 bytes), length field (1 byte), and sequence field (1 byte) */
349 chunk_size = marker->data_length - 14;
350 offset = (sequence_number - 1) * 0xffef;
351
352 /* Deal with the trivial profile (99% of images) to avoid allocating
353 * 64kb when we might only use a few kb. */
354 if (number_of_chunks == 1) {
39
Assuming 'number_of_chunks' is not equal to 1
40
Taking false branch
64
Assuming 'number_of_chunks' is not equal to 1
65
Taking false branch
355 if (context->icc_profile_size_allocated > 0)
356 goto out;
357 context->icc_profile_size = chunk_size;
358 context->icc_profile_size_allocated = chunk_size;
359 context->icc_profile = g_new (gchar, chunk_size)(gchar *) (__extension__ ({ gsize __n = (gsize) (chunk_size);
gsize __s = sizeof (gchar); 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; }))
;
360 /* copy the segment data to the profile space */
361 memcpy (context->icc_profile, marker->data + 14, chunk_size);
362 ret = TRUE1;
363 goto out;
364 }
365
366 /* There is no promise the APP2 segments are going to be in order, so we
367 * have to allocate a huge swathe of memory and fill in the gaps when
368 * (if) we get the segment.
369 * Theoretically this could be as much as 16Mb, but display profiles are
370 * vary rarely above 100kb, and printer profiles are usually less than
371 * 2Mb */
372 if (context->icc_profile_size_allocated
40.1
Field 'icc_profile_size_allocated' is equal to 0
65.1
Field 'icc_profile_size_allocated' is not equal to 0
== 0) {
41
Taking true branch
66
Taking false branch
373 context->icc_profile_size_allocated = number_of_chunks * 0xffff;
374 context->icc_profile = g_new0 (gchar, number_of_chunks * 0xffff)(gchar *) (__extension__ ({ gsize __n = (gsize) (number_of_chunks
* 0xffff); gsize __s = sizeof (gchar); 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; }))
;
42
Taking true branch
375 }
376
377 /* check the data will fit in our previously allocated buffer */
378 if (offset + chunk_size > context->icc_profile_size_allocated)
43
Assuming the condition is true
44
Taking true branch
67
Assuming the condition is false
68
Taking false branch
379 goto out;
45
Control jumps to line 389
380
381 /* copy the segment data to the profile space */
382 memcpy (context->icc_profile + offset, marker->data + 14, chunk_size);
69
Null pointer passed to 1st parameter expecting 'nonnull'
383
384 context->icc_profile_size = MAX (context->icc_profile_size, offset + chunk_size)(((context->icc_profile_size) > (offset + chunk_size)) ?
(context->icc_profile_size) : (offset + chunk_size))
;
385
386 /* success */
387 ret = TRUE1;
388out:
389 if (!ret
45.1
'ret' is 0
) {
46
Taking true branch
390 g_free (context->icc_profile);
391 context->icc_profile = NULL((void*)0);
47
Null pointer value stored to 'exif_context.icc_profile'
392 }
393 return ret;
394}
395
396static gboolean
397jpeg_parse_exif_app1 (JpegExifContext *context, jpeg_saved_marker_ptr marker)
398{
399 guint i;
400 guint ret = FALSE0;
401 guint offset;
402 guint tags; /* number of tags in current ifd */
403 guint endian = 0; /* detected endian of data */
404 const char leth[] = {0x49, 0x49, 0x2a, 0x00}; // Little endian TIFF header
405 const char beth[] = {0x4d, 0x4d, 0x00, 0x2a}; // Big endian TIFF header
406
407 /* do we have enough data? */
408 if (marker->data_length < 4)
409 goto out;
410
411 /* unique identification string */
412 if (memcmp (marker->data, "Exif", 4) != 0)
413 goto out;
414
415 /* do we have enough data? */
416 if (marker->data_length < 32)
417 goto out;
418
419 /* Just skip data until TIFF header - it should be within 16 bytes from marker start.
420 Normal structure relative to APP1 marker -
421 0x0000: APP1 marker entry = 2 bytes
422 0x0002: APP1 length entry = 2 bytes
423 0x0004: Exif Identifier entry = 6 bytes
424 0x000A: Start of TIFF header (Byte order entry) - 4 bytes
425 - This is what we look for, to determine endianess.
426 0x000E: 0th IFD offset pointer - 4 bytes
427
428 marker->data points to the first data after the APP1 marker
429 and length entries, which is the exif identification string.
430 The TIFF header should thus normally be found at i=6, below,
431 and the pointer to IFD0 will be at 6+4 = 10.
432 */
433
434 for (i=0; i<16; i++) {
435 /* little endian TIFF header */
436 if (memcmp (&marker->data[i], leth, 4) == 0) {
437 endian = G_LITTLE_ENDIAN1234;
438 ret = TRUE1;
439 break;
440 }
441
442 /* big endian TIFF header */
443 if (memcmp (&marker->data[i], beth, 4) == 0) {
444 endian = G_BIG_ENDIAN4321;
445 ret = TRUE1;
446 break;
447 }
448 }
449
450 /* could not find header */
451 if (!ret)
452 goto out;
453
454 /* read out the offset pointer to IFD0 */
455 offset = de_get32(&marker->data[i] + 4, endian);
456 i = i + offset;
457
458 /* check that we still are within the buffer and can read the tag count */
459 {
460 const size_t new_i = i + 2;
461 if (new_i < i || new_i > marker->data_length) {
462 ret = FALSE0;
463 goto out;
464 }
465
466 /* find out how many tags we have in IFD0. As per the TIFF spec, the first
467 two bytes of the IFD contain a count of the number of tags. */
468 tags = de_get16(&marker->data[i], endian);
469 i = new_i;
470 }
471
472 /* check that we still have enough data for all tags to check. The tags
473 are listed in consecutive 12-byte blocks. The tag ID, type, size, and
474 a pointer to the actual value, are packed into these 12 byte entries. */
475 {
476 const size_t new_i = i + tags * 12;
477 if (new_i < i || new_i > marker->data_length) {
478 ret = FALSE0;
479 goto out;
480 }
481 }
482
483 /* check through IFD0 for tags */
484 while (tags--) {
485 size_t new_i;
486
487 /* We check for integer overflow before the loop and
488 * at the end of each iteration */
489 guint tag = de_get16(&marker->data[i + 0], endian);
490 guint type = de_get16(&marker->data[i + 2], endian);
491 guint count = de_get32(&marker->data[i + 4], endian);
492
493 /* orientation tag? */
494 if (tag == 0x112){
495
496 /* The orientation field should consist of a single 2-byte integer,
497 * but might be a signed long.
498 * Values of types smaller than 4 bytes are stored directly in the
499 * Value Offset field */
500 if (type == 0x3 && count == 1) {
501 guint short_value = de_get16(&marker->data[i + 8], endian);
502
503 context->orientation = short_value <= 8 ? short_value : 0;
504 } else if (type == 0x9 && count == 1) {
505 guint long_value = de_get32(&marker->data[i + 8], endian);
506
507 context->orientation = long_value <= 8 ? long_value : 0;
508 }
509 }
510 /* move the pointer to the next 12-byte tag field. */
511 new_i = i + 12;
512 if (new_i < i || new_i > marker->data_length) {
513 ret = FALSE0;
514 goto out;
515 }
516 i = new_i;
517 }
518
519out:
520 return ret;
521}
522
523static void
524jpeg_parse_exif (JpegExifContext *context, j_decompress_ptr cinfo)
525{
526 jpeg_saved_marker_ptr cmarker;
527
528 /* check for interesting Exif markers */
529 cmarker = cinfo->marker_list;
530 while (cmarker != NULL((void*)0)) {
24
Assuming 'cmarker' is not equal to NULL
25
Loop condition is true. Entering loop body
49
Assuming 'cmarker' is not equal to NULL
50
Loop condition is true. Entering loop body
531 if (cmarker->marker == JPEG_APP00xE0+1)
26
Assuming the condition is false
27
Taking false branch
51
Assuming the condition is false
52
Taking false branch
532 jpeg_parse_exif_app1 (context, cmarker);
533 else if (cmarker->marker == JPEG_APP00xE0+2)
28
Assuming the condition is true
29
Taking true branch
53
Assuming the condition is true
54
Taking true branch
534 jpeg_parse_exif_app2_segment (context, cmarker);
30
Calling 'jpeg_parse_exif_app2_segment'
48
Returning from 'jpeg_parse_exif_app2_segment'
55
Calling 'jpeg_parse_exif_app2_segment'
535 cmarker = cmarker->next;
536 }
537}
538
539static gchar *
540jpeg_get_comment (j_decompress_ptr cinfo)
541{
542 jpeg_saved_marker_ptr cmarker;
543
544 cmarker = cinfo->marker_list;
545 while (cmarker != NULL((void*)0)) {
546 if (cmarker->marker == JPEG_COM0xFE)
547 return g_strndup ((const gchar *) cmarker->data, cmarker->data_length);
548 cmarker = cmarker->next;
549 }
550
551 return NULL((void*)0);
552}
553
554static void
555jpeg_destroy_exif_context (JpegExifContext *context)
556{
557 g_free (context->icc_profile);
558}
559#endif /* !NO_MODULE_ENTRIES */
560
561#ifndef NO_MODULE_ENTRIES
562/* Shared library entry point */
563static CdkPixbuf *
564cdk_pixbuf__real_jpeg_image_load (FILE *f, struct jpeg_decompress_struct *cinfo, GError **error)
565{
566 gint i;
567 char otag_str[5];
568 char *density_str;
569 CdkPixbuf * volatile pixbuf = NULL((void*)0);
570 guchar *dptr;
571 guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height,
572 * from the header file:
573 * " Usually rec_outbuf_height will be 1 or 2,
574 * at most 4."
575 */
576 guchar **lptr;
577 struct error_handler_data jerr;
578 stdio_src_ptr src;
579 gchar *icc_profile_base64;
580 gchar *comment;
581 JpegExifContext exif_context = { 0, };
582
583 /* setup error handler */
584 cinfo->err = jpeg_std_error (&jerr.pub);
585 jerr.pub.error_exit = fatal_error_handler;
586 jerr.pub.output_message = output_message_handler;
587 jerr.error = error;
588
589 if (sigsetjmp (jerr.setjmp_buffer, 1)__sigsetjmp (jerr.setjmp_buffer, 1)) {
590 /* Whoops there was a jpeg error */
591 if (pixbuf)
592 g_object_unref (pixbuf);
593
594 jpeg_destroy_decompress (cinfo);
595 jpeg_destroy_exif_context (&exif_context);
596
597 /* error should have been set by fatal_error_handler () */
598 return NULL((void*)0);
599 }
600
601 /* load header, setup */
602 jpeg_create_decompress (cinfo)jpeg_CreateDecompress((cinfo), 62, (size_t)sizeof(struct jpeg_decompress_struct
))
;
603
604 cinfo->src = (struct jpeg_source_mgr *)
605 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT0,
606 sizeof (stdio_source_mgr));
607 src = (stdio_src_ptr) cinfo->src;
608 src->buffer = (JOCTET *)
609 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT0,
610 JPEG_PROG_BUF_SIZE65536 * sizeof (JOCTET));
611
612 src->pub.init_source = stdio_init_source;
613 src->pub.fill_input_buffer = stdio_fill_input_buffer;
614 src->pub.skip_input_data = stdio_skip_input_data;
615 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
616 src->pub.term_source = stdio_term_source;
617 src->infile = f;
618 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
619 src->pub.next_input_byte = NULL((void*)0); /* until buffer loaded */
620
621 jpeg_save_markers (cinfo, JPEG_APP00xE0+1, 0xffff);
622 jpeg_save_markers (cinfo, JPEG_APP00xE0+2, 0xffff);
623 jpeg_save_markers (cinfo, JPEG_COM0xFE, 0xffff);
624 jpeg_read_header (cinfo, TRUE1);
625
626 /* parse exif data */
627 jpeg_parse_exif (&exif_context, cinfo);
628
629 jpeg_start_decompress (cinfo);
630 cinfo->do_fancy_upsampling = FALSE0;
631 cinfo->do_block_smoothing = FALSE0;
632
633 pixbuf = cdk_pixbuf_new (CDK_COLORSPACE_RGB,
634 cinfo->out_color_components == 4 ? TRUE1 : FALSE0,
635 8,
636 cinfo->output_width,
637 cinfo->output_height);
638
639 if (!pixbuf) {
640 /* broken check for *error == NULL for robustness against
641 * crappy JPEG library
642 */
643 if (error && *error == NULL((void*)0)) {
644 g_set_error_literal (error,
645 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
646 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
647 _("Insufficient memory to load image, try exiting some applications to free memory")((char *) g_dgettext ("cdk-pixbuf", "Insufficient memory to load image, try exiting some applications to free memory"
))
);
648 }
649
650 goto out;
651 }
652
653 comment = jpeg_get_comment (cinfo);
654 if (comment != NULL((void*)0)) {
655 cdk_pixbuf_set_option (pixbuf, "comment", comment);
656 g_free (comment);
657 }
658
659 switch (cinfo->density_unit) {
660 case 1:
661 /* Dots per inch (no conversion required) */
662 density_str = g_strdup_printf ("%d", cinfo->X_density);
663 cdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
664 g_free (density_str);
665 density_str = g_strdup_printf ("%d", cinfo->Y_density);
666 cdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
667 g_free (density_str);
668 break;
669 case 2:
670 /* Dots per cm - convert into dpi */
671 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->X_density)((int) round ((cinfo->X_density) * 2.54)));
672 cdk_pixbuf_set_option (pixbuf, "x-dpi", density_str);
673 g_free (density_str);
674 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->Y_density)((int) round ((cinfo->Y_density) * 2.54)));
675 cdk_pixbuf_set_option (pixbuf, "y-dpi", density_str);
676 g_free (density_str);
677 break;
678 }
679
680 /* if orientation tag was found */
681 if (exif_context.orientation != 0) {
682 g_snprintf (otag_str, sizeof (otag_str), "%d", exif_context.orientation);
683 cdk_pixbuf_set_option (pixbuf, "orientation", otag_str);
684 }
685
686 /* if icc profile was found */
687 if (exif_context.icc_profile != NULL((void*)0)) {
688 icc_profile_base64 = g_base64_encode ((const guchar *) exif_context.icc_profile, exif_context.icc_profile_size);
689 cdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
690 g_free (icc_profile_base64);
691 }
692
693 dptr = cdk_pixbuf_get_pixels (pixbuf);
694
695 /* decompress all the lines, a few at a time */
696 while (cinfo->output_scanline < cinfo->output_height) {
697 lptr = lines;
698 for (i = 0; i < cinfo->rec_outbuf_height; i++) {
699 *lptr++ = dptr;
700 dptr += cdk_pixbuf_get_rowstride (pixbuf);
701 }
702
703 jpeg_read_scanlines (cinfo, lines, cinfo->rec_outbuf_height);
704
705 switch (cinfo->out_color_space) {
706 case JCS_GRAYSCALE:
707 explode_gray_into_buf (cinfo, lines);
708 break;
709 case JCS_RGB:
710 /* do nothing */
711 break;
712 case JCS_CMYK:
713 convert_cmyk_to_rgb (cinfo, lines);
714 break;
715 default:
716 g_clear_object (&pixbuf)do { _Static_assert (sizeof *((&pixbuf)) == sizeof (gpointer
), "Expression evaluates to false"); __typeof__ (((&pixbuf
))) _pp = ((&pixbuf)); __typeof__ (*((&pixbuf))) _ptr
= *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr)
; } while (0)
;
717 g_set_error (error,
718 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
719 CDK_PIXBUF_ERROR_UNKNOWN_TYPE,
720 _("Unsupported JPEG color space (%s)")((char *) g_dgettext ("cdk-pixbuf", "Unsupported JPEG color space (%s)"
))
,
721 colorspace_name (cinfo->out_color_space));
722 goto out;
723 }
724 }
725
726out:
727 jpeg_finish_decompress (cinfo);
728 jpeg_destroy_decompress (cinfo);
729 jpeg_destroy_exif_context (&exif_context);
730
731 return pixbuf;
732}
733#endif /* !NO_MODULE_ENTRIES */
734
735#ifndef NO_MODULE_ENTRIES
736static CdkPixbuf *
737cdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
738{
739 struct jpeg_decompress_struct cinfo;
740
741 return cdk_pixbuf__real_jpeg_image_load (f, &cinfo, error);
742}
743#endif /* !NO_MODULE_ENTRIES */
744
745/**** Progressive image loading handling *****/
746
747#ifndef NO_MODULE_ENTRIES
748/* these routines required because we are acting as a source manager for */
749/* libjpeg. */
750static void
751init_source (j_decompress_ptr cinfo)
752{
753 my_src_ptr src = (my_src_ptr) cinfo->src;
754
755 src->skip_next = 0;
756}
757
758
759static void
760term_source (j_decompress_ptr cinfo)
761{
762 /* XXXX - probably should scream something has happened */
763}
764
765
766/* for progressive loading (called "I/O Suspension" by libjpeg docs) */
767/* we do nothing except return "FALSE" */
768static boolean
769fill_input_buffer (j_decompress_ptr cinfo)
770{
771 return FALSE0;
772}
773
774static void
775skip_input_data (j_decompress_ptr cinfo, long num_bytes)
776{
777 my_src_ptr src = (my_src_ptr) cinfo->src;
778 long num_can_do;
779
780 /* move as far as we can into current buffer */
781 /* then set skip_next to catch the rest */
782 if (num_bytes > 0) {
783 num_can_do = MIN (src->pub.bytes_in_buffer, num_bytes)(((src->pub.bytes_in_buffer) < (num_bytes)) ? (src->
pub.bytes_in_buffer) : (num_bytes))
;
784 src->pub.next_input_byte += (size_t) num_can_do;
785 src->pub.bytes_in_buffer -= (size_t) num_can_do;
786
787 src->skip_next = num_bytes - num_can_do;
788 }
789}
790#endif /* !NO_MODULE_ENTRIES */
791
792#ifndef NO_MODULE_ENTRIES
793/*
794 * func - called when we have pixmap created (but no image data)
795 * user_data - passed as arg 1 to func
796 * return context (opaque to user)
797 */
798static gpointer
799cdk_pixbuf__jpeg_image_begin_load (CdkPixbufModuleSizeFunc size_func,
800 CdkPixbufModulePreparedFunc prepared_func,
801 CdkPixbufModuleUpdatedFunc updated_func,
802 gpointer user_data,
803 GError **error)
804{
805 JpegProgContext *context;
806 my_source_mgr *src;
807
808 g_assert (size_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_32
= 0; if (size_func != ((void*)0)) _g_boolean_var_32 = 1; _g_boolean_var_32
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 808, ((const char*) (__func__)), "size_func != NULL"); } while
(0)
;
809 g_assert (prepared_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_33
= 0; if (prepared_func != ((void*)0)) _g_boolean_var_33 = 1;
_g_boolean_var_33; }), 1)) ; else g_assertion_message_expr (
"CdkPixbuf", "../cdk-pixbuf/io-jpeg.c", 809, ((const char*) (
__func__)), "prepared_func != NULL"); } while (0)
;
810 g_assert (updated_func != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_34
= 0; if (updated_func != ((void*)0)) _g_boolean_var_34 = 1; _g_boolean_var_34
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 810, ((const char*) (__func__)), "updated_func != NULL"); }
while (0)
;
811
812 context = g_new0 (JpegProgContext, 1)(JpegProgContext *) (__extension__ ({ gsize __n = (gsize) (1)
; gsize __s = sizeof (JpegProgContext); 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; }))
;
813 context->size_func = size_func;
814 context->prepared_func = prepared_func;
815 context->updated_func = updated_func;
816 context->user_data = user_data;
817 context->pixbuf = NULL((void*)0);
818 context->got_header = FALSE0;
819 context->did_prescan = FALSE0;
820 context->src_initialized = FALSE0;
821 context->in_output = FALSE0;
822
823 /* From jpeglib.h: "NB: you must set up the error-manager
824 * BEFORE calling jpeg_create_xxx". */
825 context->cinfo.err = jpeg_std_error (&context->jerr.pub);
826 context->jerr.pub.error_exit = fatal_error_handler;
827 context->jerr.pub.output_message = output_message_handler;
828 context->jerr.error = error;
829
830 if (sigsetjmp (context->jerr.setjmp_buffer, 1)__sigsetjmp (context->jerr.setjmp_buffer, 1)) {
831 jpeg_destroy_decompress (&context->cinfo);
832 g_free(context);
833 /* error should have been set by fatal_error_handler () */
834 return NULL((void*)0);
835 }
836
837 /* create libjpeg structures */
838 jpeg_create_decompress (&context->cinfo)jpeg_CreateDecompress((&context->cinfo), 62, (size_t)sizeof
(struct jpeg_decompress_struct))
;
839
840 context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (sizeof (my_source_mgr));
841 if (!context->cinfo.src) {
842 g_set_error_literal (error,
843 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
844 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
845 _("Couldn’t allocate memory for loading JPEG file")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading JPEG file"
))
);
846 return NULL((void*)0);
847 }
848 memset (context->cinfo.src, 0, sizeof (my_source_mgr));
849
850 src = (my_src_ptr) context->cinfo.src;
851 src->pub.init_source = init_source;
852 src->pub.fill_input_buffer = fill_input_buffer;
853 src->pub.skip_input_data = skip_input_data;
854 src->pub.resync_to_restart = jpeg_resync_to_restart;
855 src->pub.term_source = term_source;
856 src->pub.bytes_in_buffer = 0;
857 src->pub.next_input_byte = NULL((void*)0);
858
859 context->jerr.error = NULL((void*)0);
860
861 return (gpointer) context;
862}
863#endif /* NO_MODULE_ENTRIES */
864
865#ifndef NO_MODULE_ENTRIES
866/*
867 * context - returned from image_begin_load
868 *
869 * free context, unref cdk_pixbuf
870 */
871static gboolean
872cdk_pixbuf__jpeg_image_stop_load (gpointer data, GError **error)
873{
874 JpegProgContext *context = (JpegProgContext *) data;
875 struct jpeg_decompress_struct *cinfo;
876 gboolean retval;
877
878 g_return_val_if_fail (context != NULL, TRUE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_35
= 0; if (context != ((void*)0)) _g_boolean_var_35 = 1; _g_boolean_var_35
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "context != NULL"); return (1); } }
while (0)
;
879
880 cinfo = &context->cinfo;
881
882 context->jerr.error = error;
883 if (!sigsetjmp (context->jerr.setjmp_buffer, 1)__sigsetjmp (context->jerr.setjmp_buffer, 1)) {
884 /* Try to finish loading truncated files */
885 if (context->pixbuf &&
886 cinfo->output_scanline < cinfo->output_height) {
887 my_src_ptr src = (my_src_ptr) cinfo->src;
888
889 /* But only if there's enough buffer space left */
890 if (src->skip_next < sizeof(src->buffer) - 2) {
891 /* Insert a fake EOI marker */
892 src->buffer[src->skip_next] = (JOCTET) 0xFF;
893 src->buffer[src->skip_next + 1] = (JOCTET) JPEG_EOI0xD9;
894 src->pub.next_input_byte = src->buffer + src->skip_next;
895 src->pub.bytes_in_buffer = 2;
896
897 cdk_pixbuf__jpeg_image_load_lines (context, NULL((void*)0));
898 }
899 }
900 }
901
902 /* FIXME this thing needs to report errors if
903 * we have unused image data
904 */
905
906 if (context->pixbuf)
907 g_object_unref (context->pixbuf);
908
909 /* if we have an error? */
910 context->jerr.error = error;
911 if (sigsetjmp (context->jerr.setjmp_buffer, 1)__sigsetjmp (context->jerr.setjmp_buffer, 1)) {
912 retval = FALSE0;
913 } else {
914 jpeg_finish_decompress (cinfo);
915 retval = TRUE1;
916 }
917
918 jpeg_destroy_decompress (&context->cinfo);
919
920 if (cinfo->src) {
921 my_src_ptr src = (my_src_ptr) cinfo->src;
922 g_free (src);
923 }
924
925 g_free (context);
926
927 return retval;
928}
929#endif /* !NO_MODULE_ENTRIES */
930
931#ifndef NO_MODULE_ENTRIES
932static gboolean
933cdk_pixbuf__jpeg_image_load_lines (JpegProgContext *context,
934 GError **error)
935{
936 struct jpeg_decompress_struct *cinfo = &context->cinfo;
937 guchar *lines[4];
938 guchar **lptr;
939 guchar *rowptr;
940 gint nlines, i;
941
942 /* keep going until we've done all scanlines */
943 while (cinfo->output_scanline < cinfo->output_height) {
944 lptr = lines;
945 rowptr = context->dptr;
946 for (i=0; i < cinfo->rec_outbuf_height; i++) {
947 *lptr++ = rowptr;
948 rowptr += cdk_pixbuf_get_rowstride (context->pixbuf);
949 }
950
951 nlines = jpeg_read_scanlines (cinfo, lines,
952 cinfo->rec_outbuf_height);
953 if (nlines == 0)
954 break;
955
956 switch (cinfo->out_color_space) {
957 case JCS_GRAYSCALE:
958 explode_gray_into_buf (cinfo, lines);
959 break;
960 case JCS_RGB:
961 /* do nothing */
962 break;
963 case JCS_CMYK:
964 convert_cmyk_to_rgb (cinfo, lines);
965 break;
966 default:
967 g_set_error (error,
968 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
969 CDK_PIXBUF_ERROR_UNKNOWN_TYPE,
970 _("Unsupported JPEG color space (%s)")((char *) g_dgettext ("cdk-pixbuf", "Unsupported JPEG color space (%s)"
))
,
971 colorspace_name (cinfo->out_color_space));
972
973 return FALSE0;
974 }
975
976 context->dptr += (gsize)nlines * cdk_pixbuf_get_rowstride (context->pixbuf);
977
978 /* send updated signal */
979 (* context->updated_func) (context->pixbuf,
980 0,
981 cinfo->output_scanline - 1,
982 cinfo->image_width,
983 nlines,
984 context->user_data);
985 }
986
987 return TRUE1;
988}
989#endif /* NO_MODULE_ENTRIES */
990
991#ifndef NO_MODULE_ENTRIES
992/*
993 * context - from image_begin_load
994 * buf - new image data
995 * size - length of new image data
996 *
997 * append image data onto incrementally built output image
998 */
999static gboolean
1000cdk_pixbuf__jpeg_image_load_increment (gpointer data,
1001 const guchar *buf, guint size,
1002 GError **error)
1003{
1004 JpegProgContext *context = (JpegProgContext *)data;
1005 struct jpeg_decompress_struct *cinfo;
1006 my_src_ptr src;
1007 guint num_left, num_copy;
1008 guint last_num_left, last_bytes_left;
1009 guint spinguard;
1010 gboolean first;
1011 const guchar *bufhd;
1012 gint width, height;
1013 char otag_str[5];
1014 gchar *icc_profile_base64;
1015 char *density_str;
1016 JpegExifContext exif_context = { 0, };
1017 gboolean retval;
1018
1019 g_return_val_if_fail (context != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_36
= 0; if (context != ((void*)0)) _g_boolean_var_36 = 1; _g_boolean_var_36
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "context != NULL"); return (0); } }
while (0)
;
1
Assuming 'context' is not equal to null
2
Taking true branch
3
Taking true branch
4
Loop condition is false. Exiting loop
1020 g_return_val_if_fail (buf != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_37
= 0; if (buf != ((void*)0)) _g_boolean_var_37 = 1; _g_boolean_var_37
; }), 1))) { } else { g_return_if_fail_warning ("CdkPixbuf", (
(const char*) (__func__)), "buf != NULL"); return (0); } } while
(0)
;
5
Assuming 'buf' is not equal to null
6
Taking true branch
7
Taking true branch
8
Loop condition is false. Exiting loop
1021
1022 src = (my_src_ptr) context->cinfo.src;
1023
1024 cinfo = &context->cinfo;
1025
1026 context->jerr.error = error;
1027
1028 /* check for fatal error */
1029 if (sigsetjmp (context->jerr.setjmp_buffer, 1)__sigsetjmp (context->jerr.setjmp_buffer, 1)) {
9
Assuming the condition is false
10
Taking false branch
1030 retval = FALSE0;
1031 goto out;
1032 }
1033
1034 num_left = size;
1035 bufhd = buf;
1036
1037 if (num_left == 0) {
11
Assuming 'num_left' is not equal to 0
12
Taking false branch
1038 retval = TRUE1;
1039 goto out;
1040 }
1041
1042 last_num_left = num_left;
1043 last_bytes_left = 0;
1044 spinguard = 0;
1045 first = TRUE1;
1046 while (TRUE1) {
1047 /* skip over data if requested, handle unsigned int sizes cleanly */
1048 /* only can happen if we've already called jpeg_get_header */
1049 if (context->src_initialized && src->skip_next) {
13
Assuming field 'src_initialized' is 0
1050 if (src->skip_next >= num_left) {
1051 src->skip_next -= num_left;
1052 retval = TRUE1;
1053 goto out;
1054 } else {
1055 num_left -= src->skip_next;
1056 bufhd += src->skip_next;
1057 src->skip_next = 0;
1058 }
1059 }
1060
1061 /* handle any data from caller we haven't processed yet */
1062 if (num_left
13.1
'num_left' is > 0
> 0) {
1063 if(src->pub.bytes_in_buffer &&
14
Assuming field 'bytes_in_buffer' is 0
1064 src->pub.next_input_byte != src->buffer)
1065 memmove(src->buffer, src->pub.next_input_byte,
1066 src->pub.bytes_in_buffer);
1067
1068
1069 num_copy = MIN (JPEG_PROG_BUF_SIZE - src->pub.bytes_in_buffer,(((65536 - src->pub.bytes_in_buffer) < (num_left)) ? (65536
- src->pub.bytes_in_buffer) : (num_left))
15
Assuming the condition is false
16
'?' condition is false
1070 num_left)(((65536 - src->pub.bytes_in_buffer) < (num_left)) ? (65536
- src->pub.bytes_in_buffer) : (num_left))
;
1071
1072 memcpy(src->buffer + src->pub.bytes_in_buffer, bufhd,num_copy);
1073 src->pub.next_input_byte = src->buffer;
1074 src->pub.bytes_in_buffer += num_copy;
1075 bufhd += num_copy;
1076 num_left -= num_copy;
1077 }
1078
1079 /* did anything change from last pass, if not return */
1080 if (first
16.1
'first' is 1
) {
17
Taking true branch
1081 last_bytes_left = src->pub.bytes_in_buffer;
1082 first = FALSE0;
1083 } else if (src->pub.bytes_in_buffer == last_bytes_left
1084 && num_left == last_num_left) {
1085 spinguard++;
1086 } else {
1087 last_bytes_left = src->pub.bytes_in_buffer;
1088 last_num_left = num_left;
1089 }
1090
1091 /* should not go through twice and not pull bytes out of buf */
1092 if (spinguard
17.1
'spinguard' is <= 2
> 2) {
18
Taking false branch
1093 retval = TRUE1;
1094 goto out;
1095 }
1096
1097 /* try to load jpeg header */
1098 if (!context->got_header) {
19
Assuming field 'got_header' is 0
20
Taking true branch
1099 int rc;
1100 gchar* comment;
1101 gboolean has_alpha;
1102
1103 jpeg_save_markers (cinfo, JPEG_APP00xE0+1, 0xffff);
1104 jpeg_save_markers (cinfo, JPEG_APP00xE0+2, 0xffff);
1105 jpeg_save_markers (cinfo, JPEG_COM0xFE, 0xffff);
1106 rc = jpeg_read_header (cinfo, TRUE1);
1107 context->src_initialized = TRUE1;
1108
1109 /* Limit to 1GB to avoid OOM with large images */
1110 cinfo->mem->max_memory_to_use = 1024 * 1024 * 1024;
1111
1112 if (rc == JPEG_SUSPENDED0)
21
Assuming 'rc' is not equal to JPEG_SUSPENDED
22
Taking false branch
1113 continue;
1114
1115 context->got_header = TRUE1;
1116
1117 /* parse exif data */
1118 jpeg_parse_exif (&exif_context, cinfo);
23
Calling 'jpeg_parse_exif'
1119
1120 width = cinfo->image_width;
1121 height = cinfo->image_height;
1122 (* context->size_func) (&width, &height, context->user_data);
1123 if (width == 0 || height == 0) {
1124 g_set_error_literal (error,
1125 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1126 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1127 _("Transformed JPEG has zero width or height.")((char *) g_dgettext ("cdk-pixbuf", "Transformed JPEG has zero width or height."
))
);
1128 retval = FALSE0;
1129 goto out;
1130 }
1131
1132 cinfo->scale_num = 1;
1133 for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
1134 jpeg_calc_output_dimensions (cinfo);
1135 if (cinfo->output_width < width || cinfo->output_height < height) {
1136 cinfo->scale_denom /= 2;
1137 break;
1138 }
1139 }
1140 jpeg_calc_output_dimensions (cinfo);
1141
1142 if (cinfo->output_components == 3) {
1143 has_alpha = FALSE0;
1144 } else if (cinfo->output_components == 4) {
1145 has_alpha = TRUE1;
1146 } else if (cinfo->output_components == 1 &&
1147 cinfo->out_color_space == JCS_GRAYSCALE) {
1148 has_alpha = FALSE0;
1149 } else {
1150 g_set_error (error,
1151 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1152 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1153 _("Unsupported number of color components (%d)")((char *) g_dgettext ("cdk-pixbuf", "Unsupported number of color components (%d)"
))
,
1154 cinfo->output_components);
1155 retval = FALSE0;
1156 goto out;
1157 }
1158
1159 context->pixbuf = cdk_pixbuf_new (CDK_COLORSPACE_RGB,
1160 has_alpha,
1161 8,
1162 cinfo->output_width,
1163 cinfo->output_height);
1164
1165 if (context->pixbuf == NULL((void*)0)) {
1166 g_set_error_literal (error,
1167 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1168 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1169 _("Couldn’t allocate memory for loading JPEG file")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading JPEG file"
))
);
1170 retval = FALSE0;
1171 goto out;
1172 }
1173
1174 comment = jpeg_get_comment (cinfo);
1175 if (comment != NULL((void*)0)) {
1176 cdk_pixbuf_set_option (context->pixbuf, "comment", comment);
1177 g_free (comment);
1178 }
1179
1180 switch (cinfo->density_unit) {
1181 case 1:
1182 /* Dots per inch (no conversion required) */
1183 density_str = g_strdup_printf ("%d", cinfo->X_density);
1184 cdk_pixbuf_set_option (context->pixbuf, "x-dpi", density_str);
1185 g_free (density_str);
1186 density_str = g_strdup_printf ("%d", cinfo->Y_density);
1187 cdk_pixbuf_set_option (context->pixbuf, "y-dpi", density_str);
1188 g_free (density_str);
1189 break;
1190 case 2:
1191 /* Dots per cm - convert into dpi */
1192 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->X_density)((int) round ((cinfo->X_density) * 2.54)));
1193 cdk_pixbuf_set_option (context->pixbuf, "x-dpi", density_str);
1194 g_free (density_str);
1195 density_str = g_strdup_printf ("%d", DPCM_TO_DPI (cinfo->Y_density)((int) round ((cinfo->Y_density) * 2.54)));
1196 cdk_pixbuf_set_option (context->pixbuf, "y-dpi", density_str);
1197 g_free (density_str);
1198 break;
1199 }
1200
1201 /* if orientation tag was found set an option to remember its value */
1202 if (exif_context.orientation != 0) {
1203 g_snprintf (otag_str, sizeof (otag_str), "%d", exif_context.orientation);
1204 cdk_pixbuf_set_option (context->pixbuf, "orientation", otag_str);
1205 }
1206 /* if icc profile was found */
1207 if (exif_context.icc_profile != NULL((void*)0)) {
1208 icc_profile_base64 = g_base64_encode ((const guchar *) exif_context.icc_profile, exif_context.icc_profile_size);
1209 cdk_pixbuf_set_option (context->pixbuf, "icc-profile", icc_profile_base64);
1210 g_free (icc_profile_base64);
1211 }
1212
1213
1214 /* Use pixbuf buffer to store decompressed data */
1215 context->dptr = cdk_pixbuf_get_pixels (context->pixbuf);
1216
1217 /* Notify the client that we are ready to go */
1218 (* context->prepared_func) (context->pixbuf,
1219 NULL((void*)0),
1220 context->user_data);
1221
1222 } else if (!context->did_prescan) {
1223 int rc;
1224
1225 /* start decompression */
1226 cinfo->buffered_image = cinfo->progressive_mode;
1227 rc = jpeg_start_decompress (cinfo);
1228 cinfo->do_fancy_upsampling = FALSE0;
1229 cinfo->do_block_smoothing = FALSE0;
1230
1231 if (rc == JPEG_SUSPENDED0)
1232 continue;
1233
1234 context->did_prescan = TRUE1;
1235 } else if (!cinfo->buffered_image) {
1236 /* we're decompressing unbuffered so
1237 * simply get scanline by scanline from jpeg lib
1238 */
1239 if (! cdk_pixbuf__jpeg_image_load_lines (context,
1240 error)) {
1241 retval = FALSE0;
1242 goto out;
1243 }
1244
1245 if (cinfo->output_scanline >= cinfo->output_height) {
1246 retval = TRUE1;
1247 goto out;
1248 }
1249 } else {
1250 /* we're decompressing buffered (progressive)
1251 * so feed jpeg lib scanlines
1252 */
1253
1254 /* keep going until we've done all passes */
1255 while (!jpeg_input_complete (cinfo)) {
1256 if (!context->in_output) {
1257 if (jpeg_start_output (cinfo, cinfo->input_scan_number)) {
1258 context->in_output = TRUE1;
1259 context->dptr = cdk_pixbuf_get_pixels (context->pixbuf);
1260 }
1261 else
1262 break;
1263 }
1264
1265 /* get scanlines from jpeg lib */
1266 if (! cdk_pixbuf__jpeg_image_load_lines (context,
1267 error)) {
1268 retval = FALSE0;
1269 goto out;
1270 }
1271
1272 if (cinfo->output_scanline >= cinfo->output_height &&
1273 jpeg_finish_output (cinfo))
1274 context->in_output = FALSE0;
1275 else
1276 break;
1277 }
1278 if (jpeg_input_complete (cinfo)) {
1279 /* did entire image */
1280 retval = TRUE1;
1281 goto out;
1282 }
1283 else
1284 continue;
1285 }
1286 }
1287out:
1288 jpeg_destroy_exif_context (&exif_context);
1289 return retval;
1290}
1291#endif /* !NO_MODULE_ENTRIES */
1292
1293/* Save */
1294
1295#define TO_FUNCTION_BUF_SIZE4096 4096
1296
1297typedef struct {
1298 struct jpeg_destination_mgr pub;
1299 JOCTET *buffer;
1300 CdkPixbufSaveFunc save_func;
1301 gpointer user_data;
1302 GError **error;
1303} ToFunctionDestinationManager;
1304
1305void
1306to_callback_init (j_compress_ptr cinfo)
1307{
1308 ToFunctionDestinationManager *destmgr;
1309
1310 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1311 destmgr->pub.next_output_byte = destmgr->buffer;
1312 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE4096;
1313}
1314
1315static void
1316to_callback_do_write (j_compress_ptr cinfo, gsize length)
1317{
1318 ToFunctionDestinationManager *destmgr;
1319
1320 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1321 if (!destmgr->save_func ((gchar *)destmgr->buffer,
1322 length,
1323 destmgr->error,
1324 destmgr->user_data)) {
1325 struct error_handler_data *errmgr;
1326
1327 errmgr = (struct error_handler_data *) cinfo->err;
1328 /* Use a default error message if the callback didn't set one,
1329 * which it should have.
1330 */
1331 if (errmgr->error && *errmgr->error == NULL((void*)0)) {
1332 g_set_error_literal (errmgr->error,
1333 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1334 CDK_PIXBUF_ERROR_CORRUPT_IMAGE,
1335 "write function failed");
1336 }
1337 siglongjmp (errmgr->setjmp_buffer, 1);
1338 g_assert_not_reached ()do { g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 1338, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1339 }
1340}
1341
1342static boolean
1343to_callback_empty_output_buffer (j_compress_ptr cinfo)
1344{
1345 ToFunctionDestinationManager *destmgr;
1346
1347 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1348 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE4096);
1349 destmgr->pub.next_output_byte = destmgr->buffer;
1350 destmgr->pub.free_in_buffer = TO_FUNCTION_BUF_SIZE4096;
1351 return TRUE1;
1352}
1353
1354void
1355to_callback_terminate (j_compress_ptr cinfo)
1356{
1357 ToFunctionDestinationManager *destmgr;
1358
1359 destmgr = (ToFunctionDestinationManager*) cinfo->dest;
1360 to_callback_do_write (cinfo, TO_FUNCTION_BUF_SIZE4096 - destmgr->pub.free_in_buffer);
1361}
1362
1363static gboolean
1364real_save_jpeg (CdkPixbuf *pixbuf,
1365 gchar **keys,
1366 gchar **values,
1367 GError **error,
1368 gboolean to_callback,
1369 FILE *f,
1370 CdkPixbufSaveFunc save_func,
1371 gpointer user_data)
1372{
1373 /* FIXME error handling is broken */
1374
1375 struct jpeg_compress_struct cinfo;
1376 guchar *buf = NULL((void*)0);
1377 guchar *ptr;
1378 guchar *pixels = NULL((void*)0);
1379 JSAMPROW *jbuf;
1380 volatile int quality = 75; /* default; must be between 0 and 100 */
1381 int i, j;
1382 int w, h = 0;
1383 int rowstride = 0;
1384 int n_channels;
1385 struct error_handler_data jerr;
1386 ToFunctionDestinationManager to_callback_destmgr;
1387 int x_density = 0;
1388 int y_density = 0;
1389 gchar *icc_profile = NULL((void*)0);
1390 gchar *data;
1391 gint retval = TRUE1;
1392 gsize icc_profile_size = 0;
1393
1394 to_callback_destmgr.buffer = NULL((void*)0);
1395
1396 if (keys && *keys) {
1397 gchar **kiter = keys;
1398 gchar **viter = values;
1399
1400 while (*kiter) {
1401 if (strcmp (*kiter, "quality") == 0) {
1402 char *endptr = NULL((void*)0);
1403 quality = strtol (*viter, &endptr, 10);
1404
1405 if (endptr == *viter) {
1406 g_set_error (error,
1407 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1408 CDK_PIXBUF_ERROR_BAD_OPTION,
1409 _("JPEG quality must be a value between 0 and 100; value “%s” could not be parsed.")((char *) g_dgettext ("cdk-pixbuf", "JPEG quality must be a value between 0 and 100; value “%s” could not be parsed."
))
,
1410 *viter);
1411
1412 retval = FALSE0;
1413 goto cleanup;
1414 }
1415
1416 if (quality < 0 ||
1417 quality > 100) {
1418 /* This is a user-visible error;
1419 * lets people skip the range-checking
1420 * in their app.
1421 */
1422 g_set_error (error,
1423 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1424 CDK_PIXBUF_ERROR_BAD_OPTION,
1425 _("JPEG quality must be a value between 0 and 100; value “%d” is not allowed.")((char *) g_dgettext ("cdk-pixbuf", "JPEG quality must be a value between 0 and 100; value “%d” is not allowed."
))
,
1426 quality);
1427
1428 retval = FALSE0;
1429 goto cleanup;
1430 }
1431 } else if (strcmp (*kiter, "x-dpi") == 0) {
1432 char *endptr = NULL((void*)0);
1433 x_density = strtol (*viter, &endptr, 10);
1434 if (endptr == *viter)
1435 x_density = -1;
1436
1437 if (x_density <= 0 ||
1438 x_density > 65535) {
1439 /* This is a user-visible error;
1440 * lets people skip the range-checking
1441 * in their app.
1442 */
1443 g_set_error (error,
1444 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1445 CDK_PIXBUF_ERROR_BAD_OPTION,
1446 _("JPEG x-dpi must be a value between 1 and 65535; value “%s” is not allowed.")((char *) g_dgettext ("cdk-pixbuf", "JPEG x-dpi must be a value between 1 and 65535; value “%s” is not allowed."
))
,
1447 *viter);
1448
1449 retval = FALSE0;
1450 goto cleanup;
1451 }
1452 } else if (strcmp (*kiter, "y-dpi") == 0) {
1453 char *endptr = NULL((void*)0);
1454 y_density = strtol (*viter, &endptr, 10);
1455 if (endptr == *viter)
1456 y_density = -1;
1457
1458 if (y_density <= 0 ||
1459 y_density > 65535) {
1460 /* This is a user-visible error;
1461 * lets people skip the range-checking
1462 * in their app.
1463 */
1464 g_set_error (error,
1465 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1466 CDK_PIXBUF_ERROR_BAD_OPTION,
1467 _("JPEG y-dpi must be a value between 1 and 65535; value “%s” is not allowed.")((char *) g_dgettext ("cdk-pixbuf", "JPEG y-dpi must be a value between 1 and 65535; value “%s” is not allowed."
))
,
1468 *viter);
1469
1470 retval = FALSE0;
1471 goto cleanup;
1472 }
1473 } else if (strcmp (*kiter, "icc-profile") == 0) {
1474 /* decode from base64 */
1475 icc_profile = (gchar*) g_base64_decode (*viter, &icc_profile_size);
1476 if (icc_profile_size < 127) {
1477 /* This is a user-visible error */
1478 g_set_error (error,
1479 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1480 CDK_PIXBUF_ERROR_BAD_OPTION,
1481 _("Color profile has invalid length “%u”.")((char *) g_dgettext ("cdk-pixbuf", "Color profile has invalid length “%u”."
))
,
1482 (guint) icc_profile_size);
1483 retval = FALSE0;
1484 goto cleanup;
1485 }
1486 } else {
1487 g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter);
1488 }
1489
1490 ++kiter;
1491 ++viter;
1492 }
1493 }
1494
1495 rowstride = cdk_pixbuf_get_rowstride (pixbuf);
1496 n_channels = cdk_pixbuf_get_n_channels (pixbuf);
1497
1498 w = cdk_pixbuf_get_width (pixbuf);
1499 h = cdk_pixbuf_get_height (pixbuf);
1500 pixels = cdk_pixbuf_get_pixels (pixbuf);
1501
1502 /* Guaranteed by the caller. */
1503 g_assert (w >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_38
= 0; if (w >= 0) _g_boolean_var_38 = 1; _g_boolean_var_38
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 1503, ((const char*) (__func__)), "w >= 0"); } while (0)
;
1504 g_assert (h >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_39
= 0; if (h >= 0) _g_boolean_var_39 = 1; _g_boolean_var_39
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 1504, ((const char*) (__func__)), "h >= 0"); } while (0)
;
1505 g_assert (rowstride >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_40
= 0; if (rowstride >= 0) _g_boolean_var_40 = 1; _g_boolean_var_40
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 1505, ((const char*) (__func__)), "rowstride >= 0"); } while
(0)
;
1506 g_assert (n_channels >= 0)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_41
= 0; if (n_channels >= 0) _g_boolean_var_41 = 1; _g_boolean_var_41
; }), 1)) ; else g_assertion_message_expr ("CdkPixbuf", "../cdk-pixbuf/io-jpeg.c"
, 1506, ((const char*) (__func__)), "n_channels >= 0"); } while
(0)
;
1507
1508 /* Allocate a small buffer to convert image data,
1509 * and a larger buffer if doing to_callback save.
1510 */
1511 buf = g_try_malloc (w * 3 * sizeof (guchar));
1512 if (!buf) {
1513 g_set_error_literal (error,
1514 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1515 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1516 _("Couldn’t allocate memory for loading JPEG file")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading JPEG file"
))
);
1517 retval = FALSE0;
1518 goto cleanup;
1519 }
1520 if (to_callback) {
1521 to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE4096);
1522 if (!to_callback_destmgr.buffer) {
1523 g_set_error_literal (error,
1524 CDK_PIXBUF_ERRORcdk_pixbuf_error_quark (),
1525 CDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1526 _("Couldn’t allocate memory for loading JPEG file")((char *) g_dgettext ("cdk-pixbuf", "Couldn’t allocate memory for loading JPEG file"
))
);
1527 retval = FALSE0;
1528 goto cleanup;
1529 }
1530 }
1531
1532 /* set up error handling */
1533 cinfo.err = jpeg_std_error (&(jerr.pub));
1534 jerr.pub.error_exit = fatal_error_handler;
1535 jerr.pub.output_message = output_message_handler;
1536 jerr.error = error;
1537
1538 if (sigsetjmp (jerr.setjmp_buffer, 1)__sigsetjmp (jerr.setjmp_buffer, 1)) {
1539 jpeg_destroy_compress (&cinfo);
1540 retval = FALSE0;
1541 goto cleanup;
1542 }
1543
1544 /* setup compress params */
1545 jpeg_create_compress (&cinfo)jpeg_CreateCompress((&cinfo), 62, (size_t)sizeof(struct jpeg_compress_struct
))
;
1546 if (to_callback) {
1547 to_callback_destmgr.pub.init_destination = to_callback_init;
1548 to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer;
1549 to_callback_destmgr.pub.term_destination = to_callback_terminate;
1550 to_callback_destmgr.error = error;
1551 to_callback_destmgr.save_func = save_func;
1552 to_callback_destmgr.user_data = user_data;
1553 cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr;
1554 } else {
1555 jpeg_stdio_dest (&cinfo, f);
1556 }
1557 cinfo.image_width = w;
1558 cinfo.image_height = h;
1559 cinfo.input_components = 3;
1560 cinfo.in_color_space = JCS_RGB;
1561
1562 /* set up jepg compression parameters */
1563 jpeg_set_defaults (&cinfo);
1564 jpeg_set_quality (&cinfo, quality, TRUE1);
1565
1566 /* set density information */
1567 if (x_density > 0 && y_density > 0) {
1568 cinfo.density_unit = 1; /* Dots per inch */
1569 cinfo.X_density = x_density;
1570 cinfo.Y_density = y_density;
1571 }
1572
1573 jpeg_start_compress (&cinfo, TRUE1);
1574
1575 /* write ICC profile data */
1576 if (icc_profile != NULL((void*)0)) {
1577 /* optimise for the common case where only one APP2 segment is required */
1578 if (icc_profile_size < 0xffef) {
1579 data = g_new (gchar, icc_profile_size + 14)(gchar *) (__extension__ ({ gsize __n = (gsize) (icc_profile_size
+ 14); gsize __s = sizeof (gchar); 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; }))
;
1580 memcpy (data, "ICC_PROFILE\000\001\001", 14);
1581 memcpy (data + 14, icc_profile, icc_profile_size);
1582 jpeg_write_marker (&cinfo, JPEG_APP00xE0+2, (const JOCTET *) data, icc_profile_size + 14);
1583 g_free (data);
1584 } else {
1585 guint segments;
1586 guint size = 0xffef;
1587 guint offset;
1588
1589 segments = (guint) ceilf ((gfloat) icc_profile_size / (gfloat) 0xffef);
1590 data = g_new (gchar, 0xffff)(gchar *) (__extension__ ({ gsize __n = (gsize) (0xffff); gsize
__s = sizeof (gchar); 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;
}))
;
1591 memcpy (data, "ICC_PROFILE\000", 12);
1592 data[13] = segments;
1593 for (i=0; i<=segments; i++) {
1594 data[12] = i;
1595 offset = 0xffef * i;
1596
1597 /* last segment */
1598 if (i == segments)
1599 size = icc_profile_size % 0xffef;
1600
1601 memcpy (data + 14, icc_profile + offset, size);
1602 jpeg_write_marker (&cinfo, JPEG_APP00xE0+2, (const JOCTET *) data, size + 14);
1603 }
1604 g_free (data);
1605 }
1606 }
1607
1608 /* get the start pointer */
1609 ptr = pixels;
1610 /* go one scanline at a time... and save */
1611 i = 0;
1612 while (cinfo.next_scanline < cinfo.image_height) {
1613 /* convert scanline from ARGB to RGB packed */
1614 for (j = 0; j < w; j++)
1615 memcpy (&(buf[j*3]), &(ptr[(gsize)i*rowstride + j*n_channels]), 3);
1616
1617 /* write scanline */
1618 jbuf = (JSAMPROW *)(&buf);
1619 if (jpeg_write_scanlines (&cinfo, jbuf, 1) == 0) {
1620 jpeg_destroy_compress (&cinfo);
1621 retval = FALSE0;
1622 goto cleanup;
1623 }
1624
1625 i++;
1626
1627 }
1628
1629 /* finish off */
1630 jpeg_finish_compress (&cinfo);
1631 jpeg_destroy_compress(&cinfo);
1632cleanup:
1633 g_free (buf);
1634 g_free (to_callback_destmgr.buffer);
1635 g_free (icc_profile);
1636 return retval;
1637}
1638
1639static gboolean
1640cdk_pixbuf__jpeg_image_save (FILE *f,
1641 CdkPixbuf *pixbuf,
1642 gchar **keys,
1643 gchar **values,
1644 GError **error)
1645{
1646 return real_save_jpeg (pixbuf, keys, values, error,
1647 FALSE0, f, NULL((void*)0), NULL((void*)0));
1648}
1649
1650static gboolean
1651cdk_pixbuf__jpeg_image_save_to_callback (CdkPixbufSaveFunc save_func,
1652 gpointer user_data,
1653 CdkPixbuf *pixbuf,
1654 gchar **keys,
1655 gchar **values,
1656 GError **error)
1657{
1658 return real_save_jpeg (pixbuf, keys, values, error,
1659 TRUE1, NULL((void*)0), save_func, user_data);
1660}
1661
1662static gboolean
1663cdk_pixbuf__jpeg_is_save_option_supported (const gchar *option_key)
1664{
1665 if (g_strcmp0 (option_key, "quality") == 0 ||
1666 g_strcmp0 (option_key, "icc-profile") == 0)
1667 return TRUE1;
1668
1669 return FALSE0;
1670}
1671
1672#ifndef NO_MODULE_ENTRIES
1673
1674#ifndef INCLUDE_jpeg1
1675#define MODULE_ENTRY(function)void _cdk_pixbuf__jpeg_function G_MODULE_EXPORT__attribute__((visibility("default"))) void function
1676#else
1677#define MODULE_ENTRY(function)void _cdk_pixbuf__jpeg_function void _cdk_pixbuf__jpeg_ ## function
1678#endif
1679
1680MODULE_ENTRY (fill_vtable)void _cdk_pixbuf__jpeg_fill_vtable (CdkPixbufModule *module)
1681{
1682 module->load = cdk_pixbuf__jpeg_image_load;
1683 module->begin_load = cdk_pixbuf__jpeg_image_begin_load;
1684 module->stop_load = cdk_pixbuf__jpeg_image_stop_load;
1685 module->load_increment = cdk_pixbuf__jpeg_image_load_increment;
1686 module->save = cdk_pixbuf__jpeg_image_save;
1687 module->save_to_callback = cdk_pixbuf__jpeg_image_save_to_callback;
1688 module->is_save_option_supported = cdk_pixbuf__jpeg_is_save_option_supported;
1689}
1690
1691MODULE_ENTRY (fill_info)void _cdk_pixbuf__jpeg_fill_info (CdkPixbufFormat *info)
1692{
1693 static const CdkPixbufModulePattern signature[] = {
1694 { "\xff\xd8", NULL((void*)0), 100 },
1695 { NULL((void*)0), NULL((void*)0), 0 }
1696 };
1697 static const gchar *mime_types[] = {
1698 "image/jpeg",
1699 NULL((void*)0)
1700 };
1701 static const gchar *extensions[] = {
1702 "jpeg",
1703 "jpe",
1704 "jpg",
1705 NULL((void*)0)
1706 };
1707
1708 info->name = "jpeg";
1709 info->signature = (CdkPixbufModulePattern *) signature;
1710 info->description = NC_("image format", "JPEG")("JPEG");
1711 info->mime_types = (gchar **) mime_types;
1712 info->extensions = (gchar **) extensions;
1713 info->flags = CDK_PIXBUF_FORMAT_WRITABLE | CDK_PIXBUF_FORMAT_THREADSAFE;
1714 info->license = "LGPL";
1715}
1716
1717#endif