Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zimage.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, 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
1.98k
{
60
1.98k
    int code;
61
1.98k
    ref *pds;
62
63
1.98k
    check_type(*op, t_dictionary);
64
1.98k
    check_dict_read(*op);
65
1.98k
    code = dict_int_param(op, "Width", 0, max_int_in_fixed/2, -1, &pim->Width);
66
1.98k
    if (code < 0)
67
29
      return code;
68
1.95k
    code = dict_int_param(op, "Height", 0, max_int_in_fixed/2, -1, &pim->Height);
69
1.95k
    if (code < 0)
70
11
      return code;
71
1.94k
    code = dict_matrix_param(mem, op, "ImageMatrix", &pim->ImageMatrix);
72
1.94k
    if (code < 0)
73
7
      return code;
74
1.93k
    code = dict_bool_param(op, "MultipleDataSources", false, &pip->MultipleDataSources);
75
1.93k
    if (code < 0)
76
0
      return code;
77
1.93k
    code = dict_int_param(op, "BitsPerComponent", 1, max_bits_per_component, -1, &pim->BitsPerComponent);
78
1.93k
    if (code < 0)
79
2
      return code;
80
1.93k
    code = dict_bool_param(op, "Interpolate", false, &pim->Interpolate);
81
1.93k
    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
1.93k
    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
1.93k
    } else {
108
1.93k
        code = dict_floats_param(mem, op, "Decode",
109
1.93k
                                                    num_components * 2,
110
1.93k
                                                    &pim->Decode[0], NULL);
111
1.93k
        if (code < 0)
112
0
            return code;
113
1.93k
    }
114
1.93k
    pip->pDecode = &pim->Decode[0];
115
    /* Extract and check the data sources. */
116
1.93k
    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
1.93k
    if (pip->MultipleDataSources) {
122
4
        ref *ds = pip->DataSource;
123
4
        long i;
124
4
        if (!r_is_array(pds))
125
0
            return_error(gs_error_typecheck);
126
4
        if (r_size(pds) != num_components)
127
0
            return_error(gs_error_rangecheck);
128
16
        for (i = 0; i < num_components; ++i)
129
12
            array_get(mem, pds, i, &ds[i]);
130
4
        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
4
    } else
141
1.93k
        pip->DataSource[0] = *pds;
142
1.93k
    return 0;
143
1.93k
}
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
554
{
151
554
    bool islab = false;
152
554
    int num_components =
153
554
        gs_color_space_num_components(csp);
154
554
    int code;
155
156
554
    if (num_components < 1)
157
0
        return_error(gs_error_rangecheck);  /* Pattern space not allowed */
158
554
    pim->ColorSpace = csp;
159
160
554
    if (pim->ColorSpace->cmm_icc_profile_data != NULL)
161
554
        islab = pim->ColorSpace->cmm_icc_profile_data->islab;
162
163
554
    code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true,
164
554
                             num_components, max_bits_per_component, islab);
165
554
    if (code < 0)
166
49
        return code;
167
505
    pim->format =
168
505
        (pip->MultipleDataSources ? gs_image_format_component_planar :
169
505
         gs_image_format_chunky);
170
505
    return dict_bool_param(op, "CombineWithColor", false,
171
505
                           &pim->CombineWithColor);
172
554
}
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
1.93k
{
179
1.93k
    gx_image_enum_common_t *pie;
180
1.93k
    int code =
181
1.93k
        gs_image_begin_typed((const gs_image_common_t *)pim, igs,
182
1.93k
                             uses_color, false, &pie);
183
184
1.93k
    if (code < 0)
185
5
        return code;
186
1.93k
    return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie,
187
1.93k
                             sources, npop);
188
1.93k
}
189
190
/* <dict> .image1 - */
191
static int
192
zimage1(i_ctx_t *i_ctx_p)
193
554
{
194
554
    os_ptr          op = osp;
195
554
    gs_image_t      image;
196
554
    image_params    ip;
197
554
    int             code;
198
554
    gs_color_space *csp = gs_currentcolorspace(igs);
199
200
    /* Adobe interpreters accept sampled images when the current color
201
     * space is a pattern color space using the base color space instead
202
     * of the pattern space. CET 12-07a-12
203
     * If all conditions are not met the pattern color space goes through
204
     * triggering a rangecheck error.
205
     */
206
554
    if (gs_currentcpsimode(imemory) && gs_color_space_num_components(csp) < 1) {
207
0
       gs_color_space *bsp = csp->base_space;
208
0
       if (bsp)
209
0
         csp = bsp;
210
0
    }
211
212
554
    gs_image_t_init(&image, csp);
213
554
    code = pixel_image_params( i_ctx_p,
214
554
                               op,
215
554
                               (gs_pixel_image_t *)&image,
216
554
                               &ip,
217
554
                               (level2_enabled ? 16 : 8),
218
554
                               csp);
219
554
    if (code < 0)
220
49
        return code;
221
222
505
    image.Alpha = gs_image_alpha_none;
223
        /* swap Width, Height, and ImageMatrix so that it comes out the same */
224
        /* This is only for performance, so only do it for non-skew cases */
225
505
    if (image.Width == 1 && image.Height > 1 && image.BitsPerComponent == 8 &&
226
505
        image.ImageMatrix.xy == 0.0 && image.ImageMatrix.yx == 0.0 &&
227
505
        image.ImageMatrix.tx == 0.0) {
228
474
        float ftmp;
229
474
        int   itemp;
230
231
474
        itemp = image.Width;
232
474
        image.Width = image.Height;
233
474
        image.Height = itemp;
234
235
474
        image.ImageMatrix.xy = image.ImageMatrix.xx;
236
474
        image.ImageMatrix.yx = image.ImageMatrix.yy;
237
474
        image.ImageMatrix.xx = 0.0;
238
474
        image.ImageMatrix.yy = 0.0;
239
474
        ftmp = image.ImageMatrix.tx;
240
474
        image.ImageMatrix.tx = image.ImageMatrix.ty;
241
474
        image.ImageMatrix.ty = ftmp;
242
474
    }
243
505
    return zimage_setup( i_ctx_p,
244
505
                         (gs_pixel_image_t *)&image,
245
505
                         &ip.DataSource[0],
246
505
                         image.CombineWithColor,
247
505
                         1 );
248
554
}
249
250
/* <dict> .imagemask1 - */
251
static int
252
zimagemask1(i_ctx_t *i_ctx_p)
253
1.43k
{
254
1.43k
    os_ptr op = osp;
255
1.43k
    gs_image_t image;
256
1.43k
    image_params ip;
257
1.43k
    int code;
258
259
1.43k
    gs_image_t_init_mask_adjust(&image, false,
260
1.43k
                                gs_incachedevice(igs) != CACHE_DEVICE_NONE);
261
1.43k
    code = data_image_params(imemory, op, (gs_data_image_t *) & image,
262
1.43k
                             &ip, true, 1, 1, false);
263
1.43k
    if (code < 0)
264
0
        return code;
265
1.43k
    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
266
1.43k
                        true, 1);
267
1.43k
}
268
269
/* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
270
/*
271
 * We push the following on the estack.
272
 *      control mark,
273
 *  num_sources,
274
 *      for I = num_sources-1 ... 0:
275
 *          data source I,
276
 *          aliasing information:
277
 *              if source is not file, 1, except that the topmost value
278
 *      is used for bookkeeping in the procedure case (see below);
279
 *              if file is referenced by a total of M different sources and
280
 *                this is the occurrence with the lowest I, M;
281
 *              otherwise, -J, where J is the lowest I of the same file as
282
 *                this one;
283
 *      current plane index,
284
 *      num_sources,
285
 *      enumeration structure.
286
 */
287
5.77k
#define NUM_PUSH(nsource) ((nsource) * 2 + 5)
288
/*
289
 * We can access these values either from the bottom (esp at control mark - 1,
290
 * EBOT macros) or the top (esp = enumeration structure, ETOP macros).
291
 * Note that all macros return pointers.
292
 */
293
1.93k
#define EBOT_NUM_SOURCES(ep) ((ep) + 2)
294
#define EBOT_SOURCE(ep, i)\
295
1.93k
  ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2)
296
#define ETOP_SOURCE(ep, i)\
297
37.2k
  ((ep) - 4 - (i) * 2)
298
53.9k
#define ETOP_PLANE_INDEX(ep) ((ep) - 2)
299
37.2k
#define ETOP_NUM_SOURCES(ep) ((ep) - 1)
300
static int
301
zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
302
                  gx_image_enum_common_t * pie, const ref * sources, int npop)
303
1.93k
{
304
1.93k
    int num_sources = pie->num_planes;
305
1.93k
    int inumpush = NUM_PUSH(num_sources);
306
1.93k
    int code;
307
1.93k
    gs_image_enum *penum;
308
1.93k
    int px;
309
1.93k
    const ref *pp;
310
1.93k
    bool string_sources = true;
311
312
1.93k
    check_estack(inumpush + 2); /* stuff above, + continuation + proc */
313
1.93k
    make_int(EBOT_NUM_SOURCES(esp), num_sources);
314
    /*
315
     * Note that the data sources may be procedures, strings, or (Level
316
     * 2 only) files.  (The Level 1 reference manual says that Level 1
317
     * requires procedures, but Adobe Level 1 interpreters also accept
318
     * strings.)  The sources must all be of the same type.
319
     *
320
     * The Adobe documentation explicitly says that if two or more of the
321
     * data sources are the same or inter-dependent files, the result is not
322
     * defined.  We don't have a problem with the bookkeeping for
323
     * inter-dependent files, since each one has its own buffer, but we do
324
     * have to be careful if two or more sources are actually the same file.
325
     * That is the reason for the aliasing information described above.
326
     */
327
3.87k
    for (px = 0, pp = sources; px < num_sources; px++, pp++) {
328
1.93k
        es_ptr ep = EBOT_SOURCE(esp, px);
329
330
1.93k
        make_int(ep + 1, 1);  /* default is no aliasing */
331
1.93k
        switch (r_type(pp)) {
332
0
            case t_file:
333
0
                if (!level2_enabled)
334
0
                    return_error(gs_error_typecheck);
335
                /* Check for aliasing. */
336
0
                {
337
0
                    int pi;
338
339
0
                    for (pi = 0; pi < px; ++pi)
340
0
                        if (sources[pi].value.pfile == pp->value.pfile) {
341
                            /* Record aliasing */
342
0
                            make_int(ep + 1, -pi);
343
0
                            EBOT_SOURCE(esp, pi)[1].value.intval++;
344
0
                            break;
345
0
                        }
346
0
                }
347
0
                string_sources = false;
348
                /* falls through */
349
0
            case t_string:
350
0
                if (r_type(pp) != r_type(sources)) {
351
0
                    gx_image_end(pie, false);    /* Clean up pie */
352
0
                    return_error(gs_error_typecheck);
353
0
                }
354
0
                check_read(*pp);
355
0
                break;
356
1.93k
            default:
357
1.93k
                if (!r_is_proc(sources)) {
358
0
                    static const char ds[] = "DataSource";
359
0
                    gx_image_end(pie, false);    /* Clean up pie */
360
0
                    gs_errorinfo_put_pair(i_ctx_p, ds, sizeof(ds) - 1, pp);
361
0
                    return_error(gs_error_typecheck);
362
0
                }
363
1.93k
                check_proc(*pp);
364
1.93k
                string_sources = false;
365
1.93k
        }
366
1.93k
        *ep = *pp;
367
1.93k
    }
368
    /* Always place the image enumerator into local memory,
369
       because pie may have local objects inherited from igs,
370
       which may be local when the current allocation mode is global.
371
       Bug 688140. */
372
1.93k
    if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
373
0
        return_error(gs_error_VMerror);
374
1.93k
    code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
375
1.93k
    if (code != 0 || (pie->skipping && string_sources)) {   /* error, or empty image */
376
0
        int code1 = gs_image_cleanup_and_free_enum(penum, igs);
377
378
0
        if (code >= 0)   /* empty image */
379
0
            pop(npop);
380
0
        if (code >= 0 && code1 < 0)
381
0
            code = code1;
382
0
        return code;
383
0
    }
384
1.93k
    push_mark_estack(es_other, image_cleanup);
385
1.93k
    esp += inumpush - 1;
386
1.93k
    make_int(ETOP_PLANE_INDEX(esp), 0);
387
1.93k
    make_int(ETOP_NUM_SOURCES(esp), num_sources);
388
1.93k
    make_struct(esp, avm_local, penum);
389
1.93k
    switch (r_type(sources)) {
390
0
        case t_file:
391
0
            push_op_estack(image_file_continue);
392
0
            break;
393
0
        case t_string:
394
0
            push_op_estack(image_string_continue);
395
0
            break;
396
1.93k
        default:    /* procedure */
397
1.93k
            push_op_estack(image_proc_process);
398
1.93k
            break;
399
1.93k
    }
400
1.93k
    pop(npop);
401
1.93k
    return o_push_estack;
402
1.93k
}
403
/* Pop all the control information off the e-stack. */
404
static es_ptr
405
zimage_pop_estack(es_ptr tep)
406
1.91k
{
407
1.91k
    return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval);
408
1.91k
}
409
410
/*
411
 * Continuation for procedure data source.  We use the topmost aliasing slot
412
 * to remember whether we've just called the procedure (1) or whether we're
413
 * returning from a RemapColor callout (0).
414
 */
415
static int
416
image_proc_continue(i_ctx_t *i_ctx_p)
417
18.6k
{
418
18.6k
    os_ptr op = osp;
419
18.6k
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
420
18.6k
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
421
18.6k
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
422
18.6k
    uint size, used[GS_IMAGE_MAX_COMPONENTS];
423
18.6k
    gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
424
18.6k
    const byte *wanted;
425
18.6k
    int i, code;
426
427
18.6k
    if (!r_has_type_attrs(op, t_string, a_read)) {
428
1
        check_op(1);
429
        /* Procedure didn't return a (readable) string.  Quit. */
430
1
        esp = zimage_pop_estack(esp);
431
1
        image_cleanup(i_ctx_p);
432
1
        return_error(!r_has_type(op, t_string) ? gs_error_typecheck : gs_error_invalidaccess);
433
1
    }
434
18.6k
    size = r_size(op);
435
18.6k
    if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0)
436
8
        code = 1;
437
18.6k
    else {
438
42.6k
        for (i = 0; i < num_sources; i++)
439
24.0k
            plane_data[i].size = 0;
440
18.6k
        plane_data[px].data = op->value.bytes;
441
18.6k
        plane_data[px].size = size;
442
18.6k
        code = gs_image_next_planes(penum, plane_data, used);
443
18.6k
        if (code == gs_error_Remap_Color) {
444
0
            op->value.bytes += used[px]; /* skip used data */
445
0
            r_dec_size(op, used[px]);
446
0
            ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */
447
0
            return code;
448
0
        }
449
18.6k
    }
450
18.6k
    if (code) {     /* Stop now. */
451
1.91k
        esp = zimage_pop_estack(esp);
452
1.91k
        pop(1);
453
1.91k
        image_cleanup(i_ctx_p);
454
1.91k
        return (code < 0 ? code : o_pop_estack);
455
1.91k
    }
456
16.6k
    pop(1);
457
16.6k
    wanted = gs_image_planes_wanted(penum);
458
16.6k
    do {
459
16.6k
        if (++px == num_sources)
460
14.8k
            px = 0;
461
16.6k
    } while (!wanted[px]);
462
16.6k
    ETOP_PLANE_INDEX(esp)->value.intval = px;
463
16.6k
    return image_proc_process(i_ctx_p);
464
18.6k
}
465
static int
466
image_proc_process(i_ctx_t *i_ctx_p)
467
18.6k
{
468
18.6k
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
469
18.6k
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
470
18.6k
    const byte *wanted = gs_image_planes_wanted(penum);
471
18.6k
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
472
18.6k
    const ref *pp;
473
474
18.6k
    ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */
475
18.6k
    while (!wanted[px]) {
476
0
        if (++px == num_sources)
477
0
            px = 0;
478
0
        ETOP_PLANE_INDEX(esp)->value.intval = px;
479
0
    }
480
18.6k
    pp = ETOP_SOURCE(esp, px);
481
18.6k
    push_op_estack(image_proc_continue);
482
18.6k
    *++esp = *pp;
483
18.6k
    return o_push_estack;
484
18.6k
}
485
486
/* Continue processing data from an image with file data sources. */
487
static int
488
image_file_continue(i_ctx_t *i_ctx_p)
489
0
{
490
0
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
491
0
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
492
493
0
    for (;;) {
494
0
        uint min_avail = max_int;
495
0
        gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
496
0
        int code;
497
0
        int px;
498
0
        const ref *pp;
499
0
        int at_eof_count = 0;
500
0
        int total_used;
501
502
        /*
503
         * Do a first pass through the files to ensure that at least
504
         * one has data available in its buffer.
505
         */
506
507
0
        for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources;
508
0
             ++px, pp -= 2
509
0
            ) {
510
0
            int num_aliases = pp[1].value.intval;
511
0
            stream *s = pp->value.pfile;
512
0
            int min_left;
513
0
            uint avail;
514
515
0
            if (num_aliases <= 0)
516
0
                num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval;
517
0
            while ((avail = sbufavailable(s)) <=
518
0
                   (min_left = sbuf_min_left(s)) + num_aliases - 1) {
519
0
                int next = s->end_status;
520
521
0
                switch (next) {
522
0
                case 0:
523
0
                    s_process_read_buf(s);
524
0
                    continue;
525
0
                case EOFC:
526
0
                    at_eof_count++;
527
0
                    break;  /* with no data available */
528
0
                case INTC:
529
0
                case CALLC:
530
0
                    return
531
0
                        s_handle_read_exception(i_ctx_p, next, pp,
532
0
                                                NULL, 0, image_file_continue);
533
0
                default:
534
                    /* case ERRC: */
535
0
                    return_error(gs_error_ioerror);
536
0
                }
537
0
                break;   /* for EOFC */
538
0
            }
539
            /*
540
             * Note that in the EOF case, we can get here with no data
541
             * available.
542
             */
543
0
            if (avail >= min_left)
544
0
                avail = (avail - min_left) / num_aliases; /* may be 0 */
545
0
            if (avail < min_avail)
546
0
                min_avail = avail;
547
0
            plane_data[px].data = sbufptr(s);
548
0
            plane_data[px].size = avail;
549
0
        }
550
551
        /*
552
         * Now pass the available buffered data to the image processor.
553
         * Even if there is no available data, we must call
554
         * gs_image_next_planes one more time to finish processing any
555
         * retained data.
556
         */
557
558
0
        {
559
0
            int pi;
560
0
            uint used[GS_IMAGE_MAX_COMPONENTS];
561
562
0
            code = gs_image_next_planes(penum, plane_data, used);
563
            /* Now that used has been set, update the streams. */
564
0
            total_used = 0;
565
0
            for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources;
566
0
                 ++pi, pp -= 2 ) {
567
0
                (void)sbufskip(pp->value.pfile, used[pi]);
568
0
                total_used += used[pi];
569
0
            }
570
0
            if (code == gs_error_Remap_Color)
571
0
                return code;
572
0
        }
573
0
        if (at_eof_count >= num_sources || (at_eof_count && total_used == 0))
574
0
            code = 1;
575
0
        if (code) {
576
0
            int code1;
577
578
0
            esp = zimage_pop_estack(esp);
579
0
            code1 = image_cleanup(i_ctx_p);
580
0
            return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack);
581
0
        }
582
0
    }
583
0
}
584
585
/* Process data from an image with string data sources. */
586
/* This may still encounter a RemapColor callback. */
587
static int
588
image_string_continue(i_ctx_t *i_ctx_p)
589
0
{
590
0
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
591
0
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
592
0
    gs_const_string sources[GS_IMAGE_MAX_COMPONENTS];
593
0
    uint used[GS_IMAGE_MAX_COMPONENTS];
594
595
    /* Pass no data initially, to find out how much is retained. */
596
0
    memset(sources, 0, sizeof(sources[0]) * num_sources);
597
0
    for (;;) {
598
0
        int px;
599
0
        int code = gs_image_next_planes(penum, sources, used);
600
601
0
        if (code == gs_error_Remap_Color)
602
0
            return code;
603
0
    stop_now:
604
0
        if (code) {   /* Stop now. */
605
0
            esp -= NUM_PUSH(num_sources);
606
0
            image_cleanup(i_ctx_p);
607
0
            return (code < 0 ? code : o_pop_estack);
608
0
        }
609
0
        for (px = 0; px < num_sources; ++px)
610
0
            if (sources[px].size == 0) {
611
0
                const ref *psrc = ETOP_SOURCE(esp, px);
612
0
                uint size = r_size(psrc);
613
614
0
                if (size == 0) {     /* empty source */
615
0
                    code = 1;
616
0
                    goto stop_now;
617
0
                }
618
0
                sources[px].data = psrc->value.bytes;
619
0
                sources[px].size = size;
620
0
            }
621
0
    }
622
0
}
623
624
/* Clean up after enumerating an image */
625
static int
626
image_cleanup(i_ctx_t *i_ctx_p)
627
1.93k
{
628
1.93k
    es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
629
1.93k
    gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
630
631
1.93k
    return gs_image_cleanup_and_free_enum(penum, igs);
632
1.93k
}
633
634
/* ------ Initialization procedure ------ */
635
636
const op_def zimage_op_defs[] =
637
{
638
    {"1.image1", zimage1},
639
    {"1.imagemask1", zimagemask1},
640
                /* Internal operators */
641
    {"1%image_proc_continue", image_proc_continue},
642
    {"0%image_file_continue", image_file_continue},
643
    {"0%image_string_continue", image_string_continue},
644
    op_def_end(0)
645
};