GCC Code Coverage Report


Directory: src/gate/
File: src/gate/graphics/jpegimages.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 139 233 59.7%
Functions: 10 15 66.7%
Branches: 25 78 32.1%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/graphics/jpegimages.h"
30 #include "gate/results.h"
31 #include "gate/debugging.h"
32
33 #if defined(GATE_EXTLIB_LIBJPEG)
34 # define GATE_GRAPHICS_JPEG_USE_LIBJPEG
35 #else
36 # define GATE_GRAPHICS_JPEG_NO_IMPL
37 #endif
38
39 #if defined(GATE_GRAPHICS_JPEG_USE_LIBJPEG)
40
41 #include <stdio.h>
42 #include "jpeglib.h"
43 #include "jerror.h"
44 #include <setjmp.h>
45
46 typedef struct gate_jpeg_param_class
47 {
48 gate_stream_t* stream;
49 unsigned char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
50 gate_result_t result;
51 jmp_buf emergency_exit;
52 } gate_jpeg_param_t;
53
54 typedef struct gate_jpeg_error_mgr_class
55 {
56 struct jpeg_error_mgr error_mgr;
57 gate_jpeg_param_t* ptr_param;
58 } gate_jpeg_error_mgr_t;
59
60 static void gate_jpeg_error_exit(j_common_ptr cinfo)
61 {
62 /* just do nothing (instead of terminating the process which is the default) */
63 gate_jpeg_error_mgr_t* ptr_err;
64 gate_jpeg_param_t* param;
65
66 GATE_DEBUG_ASSERT(cinfo != NULL);
67 ptr_err = (gate_jpeg_error_mgr_t*)cinfo->err;
68 GATE_DEBUG_ASSERT(ptr_err != NULL);
69 param = ptr_err->ptr_param;
70 GATE_DEBUG_ASSERT(param != NULL);
71
72 GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error", cinfo->err->msg_code);
73
74 switch (cinfo->err->msg_code)
75 {
76 case JERR_UNKNOWN_MARKER:
77 {
78 GATE_DEBUG_TRACE("ignore jpeg_error: unknown marker");
79 /* ignore, do nothing */
80 break;
81 }
82 case JERR_SOI_DUPLICATE:
83 {
84 GATE_DEBUG_TRACE("ignore jpeg_error: soi duplicate");
85 /* ignore, do nothing*/
86 break;
87 }
88 case JERR_BAD_LIB_VERSION:
89 {
90 GATE_DEBUG_TRACE_MSG_VALUE("jpeg_error: bad lib version", JPEG_LIB_VERSION);
91 /* no break ! */
92 }
93 default:
94 {
95 param->result = GATE_RESULT_FAILED;
96 longjmp(param->emergency_exit, 1);
97 break;
98 }
99 }
100 }
101
102 1 static void gate_jpeg_init_source(struct jpeg_decompress_struct* decompress)
103 {
104 1 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data;
105 1 decompress->src->next_input_byte = user_param->buffer;
106 1 decompress->src->bytes_in_buffer = 0;
107 1 }
108
109 1 static boolean gate_jpeg_fill_input_buffer(struct jpeg_decompress_struct* decompress)
110 {
111 1 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)decompress->client_data;
112 gate_size_t bufferused;
113 1 gate_result_t result = gate_stream_read_block(user_param->stream, (char*)&user_param->buffer[0], sizeof(user_param->buffer), &bufferused);
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(result))
116 {
117 user_param->result = result;
118 return FALSE;
119 }
120 else
121 {
122 1 decompress->src->next_input_byte = user_param->buffer;
123 1 decompress->src->bytes_in_buffer = bufferused;
124 1 return TRUE;
125 }
126 }
127 static void gate_jpeg_skip_input_data(struct jpeg_decompress_struct* decompress, long num_bytes)
128 {
129 size_t nbytes;
130 if (num_bytes > 0)
131 {
132 nbytes = (size_t)num_bytes;
133 while (nbytes > decompress->src->bytes_in_buffer)
134 {
135 nbytes -= decompress->src->bytes_in_buffer;
136 if (!(*decompress->src->fill_input_buffer)(decompress))
137 {
138 /* error or EOF */
139 decompress->src->bytes_in_buffer = 0;
140 return;
141 }
142 }
143 decompress->src->next_input_byte += nbytes;
144 decompress->src->bytes_in_buffer -= nbytes;
145 }
146 }
147 static boolean gate_jpeg_resync_to_restart(struct jpeg_decompress_struct* decompress, int desired)
148 {
149 GATE_UNUSED_ARG(decompress);
150 GATE_UNUSED_ARG(desired);
151 return TRUE;
152 }
153 1 static void gate_jpeg_term_source(struct jpeg_decompress_struct* decompress)
154 {
155 GATE_UNUSED_ARG(decompress);
156 1 }
157
158 static boolean gate_jpeg_marker_parser(j_decompress_ptr cinfo)
159 {
160 GATE_UNUSED_ARG(cinfo);
161 /* additional markers are just "accepted" */
162 return TRUE;
163 }
164
165 1 gate_result_t gate_jpegimage_load_data(struct jpeg_decompress_struct* decompress, gate_jpeg_param_t* user_param, gate_rasterimage_t* image)
166 {
167 1 gate_result_t ret = GATE_RESULT_FAILED;
168 static const JDIMENSION jpeg_lines_to_read = 1;
169 char buffer[4096 * 3];
170 1 char* ptrbuffer = &buffer[0];
171 int jpeg_result;
172 gate_uint32_t scanline_length;
173 char* ptrbytes;
174 gate_color_t* ptrpixels;
175 gate_uint32_t x;
176 1 gate_rasterimage_t raster = GATE_INIT_EMPTY;
177
178 do
179 {
180 1 jpeg_result = jpeg_read_header(decompress, TRUE);
181
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (jpeg_result != JPEG_HEADER_OK)
183 {
184 ret = GATE_RESULT_INVALIDHEADER;
185 break;
186 }
187
188
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (FALSE == jpeg_start_decompress(decompress))
189 {
190 ret = GATE_RESULT_FAILED;
191 break;
192 }
193
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT,
195 1 (gate_uint32_t)decompress->output_width,
196 1 (gate_uint32_t)decompress->output_height, NULL))
197 {
198 ret = GATE_RESULT_OUTOFMEMORY;
199 break;
200 }
201 1 ptrpixels = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, 0);
202
203 1 scanline_length = (gate_uint32_t)decompress->output_components * raster.width;
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (scanline_length > sizeof(buffer))
205 {
206 ptrbuffer = (char*)gate_mem_alloc(scanline_length);
207 if (ptrbuffer == NULL)
208 {
209 ret = GATE_RESULT_OUTOFMEMORY;
210 break;
211 }
212 }
213
214
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
33 while (decompress->output_scanline < decompress->output_height)
215 {
216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if (jpeg_lines_to_read != jpeg_read_scanlines(decompress, (JSAMPARRAY)&ptrbuffer, jpeg_lines_to_read))
217 {
218 if (GATE_SUCCEEDED(user_param->result))
219 {
220 user_param->result = GATE_RESULT_INVALIDINPUT;
221 }
222 break;
223 }
224 32 ptrbytes = ptrbuffer;
225
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 switch (decompress->output_components)
226 {
227 case 1:
228 {
229 for (x = 0; x != raster.width; ++x)
230 {
231 ptrpixels->r = *ptrbytes;
232 ptrpixels->g = *ptrbytes;
233 ptrpixels->b = *ptrbytes;
234 ptrpixels->a = 255;
235 ++ptrbytes;
236 ++ptrpixels;
237 }
238 break;
239 }
240 32 case 3:
241 {
242
2/2
✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 32 times.
2080 for (x = 0; x != raster.width; ++x)
243 {
244 2048 ptrpixels->r = *(ptrbytes++);
245 2048 ptrpixels->g = *(ptrbytes++);
246 2048 ptrpixels->b = *(ptrbytes++);
247 2048 ptrpixels->a = 255;
248 2048 ++ptrpixels;
249 }
250 32 break;
251 }
252 default:
253 {
254 decompress->output_scanline = raster.height;
255 user_param->result = GATE_RESULT_NOTSUPPORTED;
256 break;
257 }
258 }
259
260 }
261
262 1 jpeg_finish_decompress(decompress);
263
264 1 ret = user_param->result;
265
266 } while (0);
267
268
269
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(ret))
270 {
271 1 gate_mem_copy(image, &raster, sizeof(raster));
272 1 gate_mem_clear(&raster, sizeof(raster));
273 }
274
275 1 gate_rasterimage_release(&raster);
276
277
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
278 {
279 gate_mem_dealloc(ptrbuffer);
280 }
281
282 1 return ret;
283 }
284
285 1 gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
286 {
287 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
288 1 gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY;
289 1 struct jpeg_source_mgr source_mgr = GATE_INIT_EMPTY;
290 1 struct jpeg_decompress_struct decompress = GATE_INIT_EMPTY;
291 1 gate_jpeg_param_t user_param = GATE_INIT_EMPTY;
292
293 1 user_param.stream = srcstream;
294 1 user_param.result = GATE_RESULT_OK;
295
296 1 decompress.err = jpeg_std_error(&error_mgr.error_mgr);
297 1 error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit;
298 1 error_mgr.ptr_param = &user_param;
299
300 1 jpeg_create_decompress(&decompress);
301
302 1 source_mgr.fill_input_buffer = &gate_jpeg_fill_input_buffer;
303 1 source_mgr.init_source = &gate_jpeg_init_source;
304 1 source_mgr.resync_to_restart = &gate_jpeg_resync_to_restart;
305 1 source_mgr.skip_input_data = &gate_jpeg_skip_input_data;
306 1 source_mgr.term_source = &gate_jpeg_term_source;
307 1 source_mgr.bytes_in_buffer = 0;
308 1 source_mgr.next_input_byte = NULL;
309
310 1 decompress.src = &source_mgr;
311 1 decompress.client_data = &user_param;
312
313 1 jpeg_set_marker_processor(&decompress, JPEG_COM, &gate_jpeg_marker_parser);
314 1 jpeg_set_marker_processor(&decompress, JPEG_APP0 + 12, &gate_jpeg_marker_parser);
315
316 do
317 {
318
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (0 == setjmp(user_param.emergency_exit))
319 {
320 1 ret = gate_jpegimage_load_data(&decompress, &user_param, image);
321 }
322 else /* setjmp error case */
323 {
324 /* jpeg emergency exit point reached */
325 ret = GATE_RESULT_CRITICALERROR;
326 }
327 } while (0);
328
329 1 jpeg_destroy_decompress(&decompress);
330 1 return ret;
331 }
332
333
334
335
336
337 2 static void gate_jpeg_init_destination(struct jpeg_compress_struct* compress)
338 {
339 2 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
340 2 compress->dest->free_in_buffer = sizeof(user_param->buffer);
341 2 compress->dest->next_output_byte = &user_param->buffer[0];
342 2 }
343
344 1 static boolean gate_jpeg_flush_output_buffer(struct jpeg_compress_struct* compress, gate_jpeg_param_t* user_param, gate_size_t bufferused)
345 {
346 gate_result_t result;
347 gate_size_t byteswritten;
348
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (bufferused != 0)
349 {
350 1 result = gate_stream_write_block(user_param->stream, (char const*)user_param->buffer, bufferused, &byteswritten);
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(result))
352 {
353 user_param->result = result;
354 return FALSE;
355 }
356 }
357 1 gate_jpeg_init_destination(compress);
358 1 return TRUE;
359 }
360
361 static boolean gate_jpeg_empty_output_buffer(struct jpeg_compress_struct* compress)
362 {
363 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
364 return gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer));
365 }
366
367 1 static void gate_jpeg_term_destination(struct jpeg_compress_struct* compress)
368 {
369 1 gate_jpeg_param_t* user_param = (gate_jpeg_param_t*)compress->client_data;
370
371 1 GATE_DEBUG_ASSERT(sizeof(user_param->buffer) >= compress->dest->free_in_buffer);
372 1 gate_jpeg_flush_output_buffer(compress, user_param, sizeof(user_param->buffer) - compress->dest->free_in_buffer);
373 1 }
374
375 1 static gate_result_t gate_jpegimage_save_data(gate_rasterimage_t const* image,
376 struct jpeg_destination_mgr* destination_mgr,
377 struct jpeg_compress_struct* compress,
378 gate_jpeg_param_t* user_param,
379 gate_uint8_t qualitypercent)
380 {
381 1 gate_result_t ret = GATE_RESULT_FAILED;
382 unsigned char buffer[4096 * 3];
383 1 unsigned char* ptrbuffer = &buffer[0];
384 gate_size_t required_buffer_size;
385 unsigned int y;
386 gate_uint8_t const* ptrpixels;
387 1 void(*line_writer)(gate_uint8_t*, gate_uint8_t const*, gate_size_t) = NULL;
388
389 do
390 {
391
1/11
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
1 switch (image->pixel_format)
392 {
393 case GATE_IMAGE_PIXELFORMAT_RGBA:
394 case GATE_IMAGE_PIXELFORMAT_RGB32: line_writer = &gate_color_convert_rgb_from_rgba_32; break;
395 case GATE_IMAGE_PIXELFORMAT_BGRA:
396 case GATE_IMAGE_PIXELFORMAT_BGR32: line_writer = &gate_color_convert_rgb_from_bgra_32; break;
397
398 1 case GATE_IMAGE_PIXELFORMAT_RGB24: line_writer = &gate_color_convert_rgb_from_rgb_24; break;
399 case GATE_IMAGE_PIXELFORMAT_BGR24: line_writer = &gate_color_convert_rgb_from_bgr_24; break;
400
401 case GATE_IMAGE_PIXELFORMAT_RGB555: line_writer = &gate_color_convert_rgb_from_rgb_15; break;
402 case GATE_IMAGE_PIXELFORMAT_RGB565: line_writer = &gate_color_convert_rgb_from_rgb_16; break;
403 case GATE_IMAGE_PIXELFORMAT_ARGB4: line_writer = &gate_color_convert_rgb_from_argb_16; break;
404 case GATE_IMAGE_PIXELFORMAT_YUV2: line_writer = &gate_color_convert_rgb_from_yuv2_16; break;
405
406 case GATE_IMAGE_PIXELFORMAT_PAL8: line_writer = &gate_color_convert_rgb_from_pal_8; break;
407 case GATE_IMAGE_PIXELFORMAT_GRAY8: line_writer = &gate_color_convert_rgb_from_gray_8; break;
408 default:
409 break;
410 }
411
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (NULL == line_writer)
413 {
414 ret = GATE_RESULT_NOTSUPPORTED;
415 break;
416 }
417
418 1 required_buffer_size = (gate_size_t)image->width * 3;
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (required_buffer_size > sizeof(buffer))
420 {
421 ptrbuffer = (unsigned char*)gate_mem_alloc(required_buffer_size);
422 if (ptrbuffer == NULL)
423 {
424 ret = GATE_RESULT_OUTOFMEMORY;
425 break;
426 }
427 }
428
429 1 jpeg_create_compress(compress);
430 1 compress->in_color_space = JCS_RGB;
431 1 compress->input_components = 3;
432 1 compress->image_width = (JDIMENSION)image->width;
433 1 compress->image_height = (JDIMENSION)image->height;
434 1 compress->dct_method = JDCT_FLOAT;
435
436 1 jpeg_set_defaults(compress);
437 1 compress->client_data = user_param;
438 1 compress->dest = destination_mgr;
439 1 jpeg_set_quality(compress, (int)((qualitypercent > 100) ? 100 : qualitypercent), TRUE);
440
441 1 jpeg_start_compress(compress, TRUE);
442
443
444
445
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1 times.
33 for (y = 0; y != image->height; ++y)
446 {
447 32 ptrpixels = (gate_uint8_t const*)gate_rasterimage_get_line_ptr(image, y);
448 32 line_writer(ptrbuffer, ptrpixels, image->width);
449
450
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
32 if (1 != jpeg_write_scanlines(compress, (JSAMPARRAY)&ptrbuffer, 1))
451 {
452 /* failed to write one line */
453 if (GATE_SUCCEEDED(user_param->result))
454 {
455 user_param->result = GATE_RESULT_INVALIDOUTPUT;
456 break;
457 }
458 }
459 }
460
461 1 jpeg_finish_compress(compress);
462 1 jpeg_destroy_compress(compress);
463
464 1 ret = user_param->result;
465 } while (0);
466
467
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if ((ptrbuffer != &buffer[0]) && (ptrbuffer != NULL))
468 {
469 gate_mem_dealloc(ptrbuffer);
470 }
471 1 return ret;
472 }
473
474 1 gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
475 {
476 gate_result_t ret;
477 1 gate_jpeg_param_t user_param = GATE_INIT_EMPTY;
478 1 gate_jpeg_error_mgr_t error_mgr = GATE_INIT_EMPTY;
479 1 struct jpeg_destination_mgr destination_mgr = GATE_INIT_EMPTY;
480 1 struct jpeg_compress_struct compress = GATE_INIT_EMPTY;
481 1 const gate_uint16_t qa0to15 = (gate_uint16_t)GATE_IMAGE_FLAG_DECODE_QUALITY(flags);
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 const gate_uint8_t qualitypercent = (qa0to15 > 0)
483 ? (gate_uint8_t)(qa0to15 * 100 / 15)
484 : 90;
485
486 1 user_param.result = GATE_RESULT_OK;
487 1 user_param.stream = deststream;
488
489 1 compress.err = jpeg_std_error(&error_mgr.error_mgr);
490 1 error_mgr.error_mgr.error_exit = &gate_jpeg_error_exit;
491 1 error_mgr.ptr_param = &user_param;
492
493 1 destination_mgr.empty_output_buffer = &gate_jpeg_empty_output_buffer;
494 1 destination_mgr.init_destination = &gate_jpeg_init_destination;
495 1 destination_mgr.term_destination = &gate_jpeg_term_destination;
496 1 destination_mgr.free_in_buffer = 0;
497 1 destination_mgr.next_output_byte = NULL;
498
499 do
500 {
501
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (0 == setjmp(user_param.emergency_exit))
502 {
503 1 ret = gate_jpegimage_save_data(image, &destination_mgr, &compress, &user_param, qualitypercent);
504 }
505 else /* setjmp error case */
506 {
507 /* jpeg emergency exit point reached */
508 ret = GATE_RESULT_CRITICALERROR;
509 }
510 } while (0);
511 1 return ret;
512 }
513
514 #endif /* GATE_GRAPHICS_JPEG_USE_LIBJPEG */
515
516 #if defined(GATE_GRAPHICS_JPEG_NO_IMPL)
517
518 gate_result_t gate_jpegimage_load(gate_stream_t* srcstream, gate_rasterimage_t* image, gate_enumint_t flags)
519 {
520 (void)srcstream;
521 (void)image;
522 (void)flags;
523 return GATE_RESULT_NOTIMPLEMENTED;
524 }
525
526 gate_result_t gate_jpegimage_save(gate_rasterimage_t const* image, gate_stream_t* deststream, gate_enumint_t flags)
527 {
528 (void)image;
529 (void)deststream;
530 (void)flags;
531 return GATE_RESULT_NOTIMPLEMENTED;
532 }
533
534 #endif
535
536