Coverage Report

Created: 2025-06-10 07:19

/src/ghostpdl/psi/zimage.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Image operators */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "stat_.h" /* get system header early to avoid name clash on Cygwin */
21
#include "ghost.h"
22
#include "oper.h"
23
#include "gscolor.h"
24
#include "gscspace.h"
25
#include "gscolor2.h"
26
#include "gsmatrix.h"
27
#include "gsimage.h"
28
#include "gxfixed.h"
29
#include "gsstruct.h"
30
#include "gxiparam.h"
31
#include "idict.h"
32
#include "idparam.h"
33
#include "estack.h"   /* for image[mask] */
34
#include "ialloc.h"
35
#include "igstate.h"
36
#include "ilevel.h"
37
#include "store.h"
38
#include "stream.h"
39
#include "ifilter.h"    /* for stream exception handling */
40
#include "iimage.h"
41
#include "gxcspace.h"
42
43
/* Forward references */
44
static int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
45
                                 gx_image_enum_common_t * pie,
46
                                 const ref * sources, int npop);
47
static int image_proc_process(i_ctx_t *);
48
static int image_file_continue(i_ctx_t *);
49
static int image_string_continue(i_ctx_t *);
50
static int image_cleanup(i_ctx_t *);
51
52
/* Extract and check the parameters for a gs_data_image_t. */
53
int
54
data_image_params(const gs_memory_t *mem,
55
                  const ref *op, gs_data_image_t *pim,
56
                  image_params *pip, bool require_DataSource,
57
                  int num_components, int max_bits_per_component,
58
                  bool islab)
59
98.6k
{
60
98.6k
    int code;
61
98.6k
    ref *pds;
62
63
98.6k
    check_type(*op, t_dictionary);
64
98.6k
    check_dict_read(*op);
65
98.6k
    code = dict_int_param(op, "Width", 0, max_int_in_fixed/2, -1, &pim->Width);
66
98.6k
    if (code < 0)
67
1
      return code;
68
98.6k
    code = dict_int_param(op, "Height", 0, max_int_in_fixed/2, -1, &pim->Height);
69
98.6k
    if (code < 0)
70
1
      return code;
71
98.6k
    code = dict_matrix_param(mem, op, "ImageMatrix", &pim->ImageMatrix);
72
98.6k
    if (code < 0)
73
1
      return code;
74
98.6k
    code = dict_bool_param(op, "MultipleDataSources", false, &pip->MultipleDataSources);
75
98.6k
    if (code < 0)
76
0
      return code;
77
98.6k
    code = dict_int_param(op, "BitsPerComponent", 1, max_bits_per_component, -1, &pim->BitsPerComponent);
78
98.6k
    if (code < 0)
79
0
      return code;
80
98.6k
    code = dict_bool_param(op, "Interpolate", false, &pim->Interpolate);
81
98.6k
    if (code < 0)
82
0
      return code;
83
84
    /* Decode size pulled out of here to catch case of Lab color space which
85
       has a 4 entry range.  We also do NOT want to do Lab decoding IF range
86
       is the common -128 127 for a and b. Otherwise we end up doing multiple
87
       decode operations, since ICC flow will expect encoded data.
88
       That is resolved later.  Also discovered that PDF write will stick
89
       6 entry range in wich appears to be OK as far as AR is concerned so
90
       we have to handle that too. */
91
98.6k
    if (islab) {
92
        /* Note that it is possible that only the ab range values are there
93
           or the lab values.  I have seen both cases.... */
94
0
        code = dict_floats_param(mem, op, "Decode", 4,
95
0
                                 &pim->Decode[2], NULL);
96
0
        if (code < 0) {
97
            /* Try for all three */
98
0
            code = dict_floats_param(mem, op, "Decode", 6,
99
0
                                                        &pim->Decode[0], NULL);
100
0
        } else {
101
            /* Set the range on the L */
102
0
            pim->Decode[0] = 0;
103
0
            pim->Decode[1] = 100.0;
104
0
        }
105
0
        if (code < 0)
106
0
            return code;
107
98.6k
    } else {
108
98.6k
        code = dict_floats_param(mem, op, "Decode",
109
98.6k
                                                    num_components * 2,
110
98.6k
                                                    &pim->Decode[0], NULL);
111
98.6k
        if (code < 0)
112
0
            return code;
113
98.6k
    }
114
98.6k
    pip->pDecode = &pim->Decode[0];
115
    /* Extract and check the data sources. */
116
98.6k
    if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
117
0
        if (require_DataSource)
118
0
            return (code < 0 ? code : gs_note_error(gs_error_rangecheck));
119
0
        return 1;   /* no data source */
120
0
    }
121
98.6k
    if (pip->MultipleDataSources) {
122
0
        ref *ds = pip->DataSource;
123
0
        long i;
124
0
        if (!r_is_array(pds))
125
0
            return_error(gs_error_typecheck);
126
0
        if (r_size(pds) != num_components)
127
0
            return_error(gs_error_rangecheck);
128
0
        for (i = 0; i < num_components; ++i)
129
0
            array_get(mem, pds, i, &ds[i]);
130
0
        if (r_type(&ds[0]) == t_string) {
131
            /* We don't have a problem with the strings of different length
132
             * but Adobe does and CET tast 12-02.ps reports this as an error.
133
             */
134
0
            for (i = 1; i < num_components; ++i) {
135
0
                if (r_type(&ds[i]) == t_string && r_size(&ds[i]) != r_size(&ds[0])) {
136
0
                    return_error(gs_error_rangecheck);
137
0
                }
138
0
            }
139
0
        }
140
0
    } else
141
98.6k
        pip->DataSource[0] = *pds;
142
98.6k
    return 0;
143
98.6k
}
144
145
/* Extract and check the parameters for a gs_pixel_image_t. */
146
int
147
pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
148
                   image_params *pip, int max_bits_per_component,
149
                   gs_color_space *csp)
150
13
{
151
13
    bool islab = false;
152
13
    int num_components =
153
13
        gs_color_space_num_components(csp);
154
13
    int code;
155
156
13
    if (num_components < 1)
157
0
        return_error(gs_error_rangecheck);  /* Pattern space not allowed */
158
13
    pim->ColorSpace = csp;
159
160
13
    if (pim->ColorSpace->cmm_icc_profile_data != NULL)
161
13
        islab = pim->ColorSpace->cmm_icc_profile_data->islab;
162
163
13
    code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true,
164
13
                             num_components, max_bits_per_component, islab);
165
13
    if (code < 0)
166
2
        return code;
167
11
    pim->format =
168
11
        (pip->MultipleDataSources ? gs_image_format_component_planar :
169
11
         gs_image_format_chunky);
170
11
    return dict_bool_param(op, "CombineWithColor", false,
171
11
                           &pim->CombineWithColor);
172
13
}
173
174
/* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
175
int
176
zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
177
             const ref * sources, bool uses_color, int npop)
178
98.6k
{
179
98.6k
    gx_image_enum_common_t *pie;
180
98.6k
    int code =
181
98.6k
        gs_image_begin_typed((const gs_image_common_t *)pim, igs,
182
98.6k
                             uses_color, false, &pie);
183
184
98.6k
    if (code < 0)
185
1
        return code;
186
98.6k
    return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie,
187
98.6k
                             sources, npop);
188
98.6k
}
189
190
/* <dict> .image1 - */
191
static int
192
zimage1(i_ctx_t *i_ctx_p)
193
13
{
194
13
    os_ptr          op = osp;
195
13
    gs_image_t      image;
196
13
    image_params    ip;
197
13
    int             code;
198
13
    gs_color_space *csp = gs_currentcolorspace(igs);
199
200
13
    check_op(1);
201
    /* Adobe interpreters accept sampled images when the current color
202
     * space is a pattern color space using the base color space instead
203
     * of the pattern space. CET 12-07a-12
204
     * If all conditions are not met the pattern color space goes through
205
     * triggering a rangecheck error.
206
     */
207
13
    if (gs_currentcpsimode(imemory) && gs_color_space_num_components(csp) < 1) {
208
0
       gs_color_space *bsp = csp->base_space;
209
0
       if (bsp)
210
0
         csp = bsp;
211
0
    }
212
213
13
    gs_image_t_init(&image, csp);
214
13
    code = pixel_image_params( i_ctx_p,
215
13
                               op,
216
13
                               (gs_pixel_image_t *)&image,
217
13
                               &ip,
218
13
                               (level2_enabled ? 16 : 8),
219
13
                               csp);
220
13
    if (code < 0)
221
2
        return code;
222
223
11
    image.Alpha = gs_image_alpha_none;
224
        /* swap Width, Height, and ImageMatrix so that it comes out the same */
225
        /* This is only for performance, so only do it for non-skew cases */
226
11
    if (image.Width == 1 && image.Height > 1 && image.BitsPerComponent == 8 &&
227
11
        image.ImageMatrix.xy == 0.0 && image.ImageMatrix.yx == 0.0 &&
228
11
        image.ImageMatrix.tx == 0.0) {
229
0
        float ftmp;
230
0
        int   itemp;
231
232
0
        itemp = image.Width;
233
0
        image.Width = image.Height;
234
0
        image.Height = itemp;
235
236
0
        image.ImageMatrix.xy = image.ImageMatrix.xx;
237
0
        image.ImageMatrix.yx = image.ImageMatrix.yy;
238
0
        image.ImageMatrix.xx = 0.0;
239
0
        image.ImageMatrix.yy = 0.0;
240
0
        ftmp = image.ImageMatrix.tx;
241
0
        image.ImageMatrix.tx = image.ImageMatrix.ty;
242
0
        image.ImageMatrix.ty = ftmp;
243
0
    }
244
11
    return zimage_setup( i_ctx_p,
245
11
                         (gs_pixel_image_t *)&image,
246
11
                         &ip.DataSource[0],
247
11
                         image.CombineWithColor,
248
11
                         1 );
249
13
}
250
251
/* <dict> .imagemask1 - */
252
static int
253
zimagemask1(i_ctx_t *i_ctx_p)
254
98.6k
{
255
98.6k
    os_ptr op = osp;
256
98.6k
    gs_image_t image;
257
98.6k
    image_params ip;
258
98.6k
    int code;
259
260
98.6k
    check_op(1);
261
98.6k
    gs_image_t_init_mask_adjust(&image, false,
262
98.6k
                                gs_incachedevice(igs) != CACHE_DEVICE_NONE);
263
98.6k
    code = data_image_params(imemory, op, (gs_data_image_t *) & image,
264
98.6k
                             &ip, true, 1, 1, false);
265
98.6k
    if (code < 0)
266
1
        return code;
267
98.6k
    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
268
98.6k
                        true, 1);
269
98.6k
}
270
271
/* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
272
/*
273
 * We push the following on the estack.
274
 *      control mark,
275
 *  num_sources,
276
 *      for I = num_sources-1 ... 0:
277
 *          data source I,
278
 *          aliasing information:
279
 *              if source is not file, 1, except that the topmost value
280
 *      is used for bookkeeping in the procedure case (see below);
281
 *              if file is referenced by a total of M different sources and
282
 *                this is the occurrence with the lowest I, M;
283
 *              otherwise, -J, where J is the lowest I of the same file as
284
 *                this one;
285
 *      current plane index,
286
 *      num_sources,
287
 *      enumeration structure.
288
 */
289
295k
#define NUM_PUSH(nsource) ((nsource) * 2 + 5)
290
/*
291
 * We can access these values either from the bottom (esp at control mark - 1,
292
 * EBOT macros) or the top (esp = enumeration structure, ETOP macros).
293
 * Note that all macros return pointers.
294
 */
295
98.6k
#define EBOT_NUM_SOURCES(ep) ((ep) + 2)
296
#define EBOT_SOURCE(ep, i)\
297
98.6k
  ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2)
298
#define ETOP_SOURCE(ep, i)\
299
4.92M
  ((ep) - 4 - (i) * 2)
300
7.26M
#define ETOP_PLANE_INDEX(ep) ((ep) - 2)
301
4.90M
#define ETOP_NUM_SOURCES(ep) ((ep) - 1)
302
static int
303
zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
304
                  gx_image_enum_common_t * pie, const ref * sources, int npop)
305
98.6k
{
306
98.6k
    int num_sources = pie->num_planes;
307
98.6k
    int inumpush = NUM_PUSH(num_sources);
308
98.6k
    int code;
309
98.6k
    gs_image_enum *penum;
310
98.6k
    int px;
311
98.6k
    const ref *pp;
312
98.6k
    bool string_sources = true;
313
314
98.6k
    check_estack(inumpush + 2); /* stuff above, + continuation + proc */
315
98.6k
    make_int(EBOT_NUM_SOURCES(esp), num_sources);
316
    /*
317
     * Note that the data sources may be procedures, strings, or (Level
318
     * 2 only) files.  (The Level 1 reference manual says that Level 1
319
     * requires procedures, but Adobe Level 1 interpreters also accept
320
     * strings.)  The sources must all be of the same type.
321
     *
322
     * The Adobe documentation explicitly says that if two or more of the
323
     * data sources are the same or inter-dependent files, the result is not
324
     * defined.  We don't have a problem with the bookkeeping for
325
     * inter-dependent files, since each one has its own buffer, but we do
326
     * have to be careful if two or more sources are actually the same file.
327
     * That is the reason for the aliasing information described above.
328
     */
329
197k
    for (px = 0, pp = sources; px < num_sources; px++, pp++) {
330
98.6k
        es_ptr ep = EBOT_SOURCE(esp, px);
331
332
98.6k
        make_int(ep + 1, 1);  /* default is no aliasing */
333
98.6k
        switch (r_type(pp)) {
334
0
            case t_file:
335
0
                if (!level2_enabled)
336
0
                    return_error(gs_error_typecheck);
337
                /* Check for aliasing. */
338
0
                {
339
0
                    int pi;
340
341
0
                    for (pi = 0; pi < px; ++pi)
342
0
                        if (sources[pi].value.pfile == pp->value.pfile) {
343
                            /* Record aliasing */
344
0
                            make_int(ep + 1, -pi);
345
0
                            EBOT_SOURCE(esp, pi)[1].value.intval++;
346
0
                            break;
347
0
                        }
348
0
                }
349
0
                string_sources = false;
350
                /* falls through */
351
1
            case t_string:
352
1
                if (r_type(pp) != r_type(sources)) {
353
0
                    gx_image_end(pie, false);    /* Clean up pie */
354
0
                    return_error(gs_error_typecheck);
355
0
                }
356
1
                check_read(*pp);
357
1
                break;
358
98.6k
            default:
359
98.6k
                if (!r_is_proc(sources)) {
360
0
                    static const char ds[] = "DataSource";
361
0
                    gx_image_end(pie, false);    /* Clean up pie */
362
0
                    gs_errorinfo_put_pair(i_ctx_p, ds, sizeof(ds) - 1, pp);
363
0
                    return_error(gs_error_typecheck);
364
0
                }
365
98.6k
                check_proc(*pp);
366
98.6k
                string_sources = false;
367
98.6k
        }
368
98.6k
        *ep = *pp;
369
98.6k
    }
370
    /* Always place the image enumerator into local memory,
371
       because pie may have local objects inherited from igs,
372
       which may be local when the current allocation mode is global.
373
       Bug 688140. */
374
98.6k
    if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
375
0
        return_error(gs_error_VMerror);
376
98.6k
    code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
377
98.6k
    if (code != 0 || (pie->skipping && string_sources)) {   /* error, or empty image */
378
7
        int code1 = gs_image_cleanup_and_free_enum(penum, igs);
379
380
7
        if (code >= 0)   /* empty image */
381
7
            pop(npop);
382
7
        if (code >= 0 && code1 < 0)
383
0
            code = code1;
384
7
        return code;
385
7
    }
386
98.6k
    push_mark_estack(es_other, image_cleanup);
387
98.6k
    esp += inumpush - 1;
388
98.6k
    make_int(ETOP_PLANE_INDEX(esp), 0);
389
98.6k
    make_int(ETOP_NUM_SOURCES(esp), num_sources);
390
98.6k
    make_struct(esp, avm_local, penum);
391
98.6k
    switch (r_type(sources)) {
392
0
        case t_file:
393
0
            push_op_estack(image_file_continue);
394
0
            break;
395
1
        case t_string:
396
1
            push_op_estack(image_string_continue);
397
1
            break;
398
98.6k
        default:    /* procedure */
399
98.6k
            push_op_estack(image_proc_process);
400
98.6k
            break;
401
98.6k
    }
402
98.6k
    pop(npop);
403
98.6k
    return o_push_estack;
404
98.6k
}
405
/* Pop all the control information off the e-stack. */
406
static es_ptr
407
zimage_pop_estack(es_ptr tep)
408
98.6k
{
409
98.6k
    return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval);
410
98.6k
}
411
412
/*
413
 * Continuation for procedure data source.  We use the topmost aliasing slot
414
 * to remember whether we've just called the procedure (1) or whether we're
415
 * returning from a RemapColor callout (0).
416
 */
417
static int
418
image_proc_continue(i_ctx_t *i_ctx_p)
419
2.45M
{
420
2.45M
    os_ptr op = osp;
421
2.45M
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
422
2.45M
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
423
2.45M
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
424
2.45M
    uint size, used[GS_IMAGE_MAX_COMPONENTS];
425
2.45M
    gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
426
2.45M
    const byte *wanted;
427
2.45M
    int i, code;
428
429
2.45M
    if (!r_has_type_attrs(op, t_string, a_read)) {
430
8
        check_op(1);
431
        /* Procedure didn't return a (readable) string.  Quit. */
432
1
        esp = zimage_pop_estack(esp);
433
1
        image_cleanup(i_ctx_p);
434
1
        return_error(!r_has_type(op, t_string) ? gs_error_typecheck : gs_error_invalidaccess);
435
8
    }
436
2.45M
    size = r_size(op);
437
2.45M
    if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0)
438
10
        code = 1;
439
2.45M
    else {
440
4.90M
        for (i = 0; i < num_sources; i++)
441
2.45M
            plane_data[i].size = 0;
442
443
        /* Make a copy of the string source data in 'stable' memory (immune to save/restore)
444
         * We need this because of bug #706867 where one of the procedure data sources does
445
         * a 'restore' back to a point where the string returned (and saved) by one of the
446
         * other procedure data sources is freed. By copying the string to stable memory
447
         * this can't happen.
448
         */
449
2.45M
        plane_data[px].data = gs_alloc_string(imemory->stable_memory, size, "image_proc_continue");
450
2.45M
        if (plane_data[px].data == NULL)
451
0
            return_error(gs_error_VMerror);
452
2.45M
        memcpy((byte *)plane_data[px].data, op->value.bytes, size);
453
2.45M
        plane_data[px].size = size;
454
        /* Set the txfer_control flag to true to transfer control of the string (which must be allocated
455
         * in stable memory for this) to the gs_image_next_planes() routine.
456
         */
457
2.45M
        code = gs_image_next_planes(penum, plane_data, used, true);
458
2.45M
        if (code == gs_error_Remap_Color) {
459
0
            op->value.bytes += used[px]; /* skip used data */
460
0
            r_dec_size(op, used[px]);
461
0
            ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */
462
0
            return code;
463
0
        }
464
2.45M
    }
465
2.45M
    if (code) {     /* Stop now. */
466
98.6k
        esp = zimage_pop_estack(esp);
467
98.6k
        pop(1);
468
98.6k
        image_cleanup(i_ctx_p);
469
98.6k
        return (code < 0 ? code : o_pop_estack);
470
98.6k
    }
471
2.35M
    pop(1);
472
2.35M
    wanted = gs_image_planes_wanted(penum);
473
2.35M
    do {
474
2.35M
        if (++px == num_sources)
475
2.35M
            px = 0;
476
2.35M
    } while (!wanted[px]);
477
2.35M
    ETOP_PLANE_INDEX(esp)->value.intval = px;
478
2.35M
    return image_proc_process(i_ctx_p);
479
2.45M
}
480
static int
481
image_proc_process(i_ctx_t *i_ctx_p)
482
2.45M
{
483
2.45M
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
484
2.45M
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
485
2.45M
    const byte *wanted = gs_image_planes_wanted(penum);
486
2.45M
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
487
2.45M
    const ref *pp;
488
489
2.45M
    ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */
490
2.45M
    while (!wanted[px]) {
491
0
        if (++px == num_sources)
492
0
            px = 0;
493
0
        ETOP_PLANE_INDEX(esp)->value.intval = px;
494
0
    }
495
2.45M
    pp = ETOP_SOURCE(esp, px);
496
2.45M
    push_op_estack(image_proc_continue);
497
2.45M
    *++esp = *pp;
498
2.45M
    return o_push_estack;
499
2.45M
}
500
501
/* Continue processing data from an image with file data sources. */
502
static int
503
image_file_continue(i_ctx_t *i_ctx_p)
504
0
{
505
0
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
506
0
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
507
508
0
    for (;;) {
509
0
        uint min_avail = max_int;
510
0
        gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
511
0
        int code;
512
0
        int px;
513
0
        const ref *pp;
514
0
        int at_eof_count = 0;
515
0
        int total_used;
516
517
        /*
518
         * Do a first pass through the files to ensure that at least
519
         * one has data available in its buffer.
520
         */
521
522
0
        for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources;
523
0
             ++px, pp -= 2
524
0
            ) {
525
0
            int num_aliases = pp[1].value.intval;
526
0
            stream *s = pp->value.pfile;
527
0
            int min_left;
528
0
            uint avail;
529
530
0
            if (num_aliases <= 0)
531
0
                num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval;
532
0
            while ((avail = sbufavailable(s)) <=
533
0
                   (min_left = sbuf_min_left(s)) + num_aliases - 1) {
534
0
                int next = s->end_status;
535
536
0
                switch (next) {
537
0
                case 0:
538
0
                    s_process_read_buf(s);
539
0
                    continue;
540
0
                case EOFC:
541
0
                    at_eof_count++;
542
0
                    break;  /* with no data available */
543
0
                case INTC:
544
0
                case CALLC:
545
0
                    return
546
0
                        s_handle_read_exception(i_ctx_p, next, pp,
547
0
                                                NULL, 0, image_file_continue);
548
0
                default:
549
                    /* case ERRC: */
550
0
                    return_error(gs_error_ioerror);
551
0
                }
552
0
                break;   /* for EOFC */
553
0
            }
554
            /*
555
             * Note that in the EOF case, we can get here with no data
556
             * available.
557
             */
558
0
            if (avail >= min_left)
559
0
                avail = (avail - min_left) / num_aliases; /* may be 0 */
560
0
            if (avail < min_avail)
561
0
                min_avail = avail;
562
0
            plane_data[px].data = sbufptr(s);
563
0
            plane_data[px].size = avail;
564
0
        }
565
566
        /*
567
         * Now pass the available buffered data to the image processor.
568
         * Even if there is no available data, we must call
569
         * gs_image_next_planes one more time to finish processing any
570
         * retained data.
571
         */
572
573
0
        {
574
0
            int pi;
575
0
            uint used[GS_IMAGE_MAX_COMPONENTS];
576
577
0
            code = gs_image_next_planes(penum, plane_data, used, false);
578
            /* Now that used has been set, update the streams. */
579
0
            total_used = 0;
580
0
            for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources;
581
0
                 ++pi, pp -= 2 ) {
582
0
                (void)sbufskip(pp->value.pfile, used[pi]);
583
0
                total_used += used[pi];
584
0
            }
585
0
            if (code == gs_error_Remap_Color)
586
0
                return code;
587
0
        }
588
0
        if (at_eof_count >= num_sources || (at_eof_count && total_used == 0))
589
0
            code = 1;
590
0
        if (code) {
591
0
            int code1;
592
593
0
            esp = zimage_pop_estack(esp);
594
0
            code1 = image_cleanup(i_ctx_p);
595
0
            return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack);
596
0
        }
597
0
    }
598
0
}
599
600
/* Process data from an image with string data sources. */
601
/* This may still encounter a RemapColor callback. */
602
static int
603
image_string_continue(i_ctx_t *i_ctx_p)
604
1
{
605
1
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
606
1
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
607
1
    gs_const_string sources[GS_IMAGE_MAX_COMPONENTS];
608
1
    uint used[GS_IMAGE_MAX_COMPONENTS];
609
610
    /* Pass no data initially, to find out how much is retained. */
611
1
    memset(sources, 0, sizeof(sources[0]) * num_sources);
612
21.8k
    for (;;) {
613
21.8k
        int px;
614
21.8k
        int code = gs_image_next_planes(penum, sources, used, false);
615
616
21.8k
        if (code == gs_error_Remap_Color)
617
0
            return code;
618
21.8k
    stop_now:
619
21.8k
        if (code) {   /* Stop now. */
620
1
            esp -= NUM_PUSH(num_sources);
621
1
            image_cleanup(i_ctx_p);
622
1
            return (code < 0 ? code : o_pop_estack);
623
1
        }
624
43.7k
        for (px = 0; px < num_sources; ++px)
625
21.8k
            if (sources[px].size == 0) {
626
21.8k
                const ref *psrc = ETOP_SOURCE(esp, px);
627
21.8k
                uint size = r_size(psrc);
628
629
21.8k
                if (size == 0) {     /* empty source */
630
0
                    code = 1;
631
0
                    goto stop_now;
632
0
                }
633
21.8k
                sources[px].data = psrc->value.bytes;
634
21.8k
                sources[px].size = size;
635
21.8k
            }
636
21.8k
    }
637
1
}
638
639
/* Clean up after enumerating an image */
640
static int
641
image_cleanup(i_ctx_t *i_ctx_p)
642
98.6k
{
643
98.6k
    es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
644
98.6k
    gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
645
646
98.6k
    return gs_image_cleanup_and_free_enum(penum, igs);
647
98.6k
}
648
649
/* ------ Initialization procedure ------ */
650
651
const op_def zimage_op_defs[] =
652
{
653
    {"1.image1", zimage1},
654
    {"1.imagemask1", zimagemask1},
655
                /* Internal operators */
656
    {"1%image_proc_continue", image_proc_continue},
657
    {"0%image_file_continue", image_file_continue},
658
    {"0%image_string_continue", image_string_continue},
659
    op_def_end(0)
660
};