Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxclread.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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
/* Command list reading for Ghostscript. */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gp.h"     /* for gp_fmode_rb */
21
#include "gpcheck.h"
22
#include "gserrors.h"
23
#include "gxdevice.h"
24
#include "gscoord.h"    /* requires gsmatrix.h */
25
#include "gsdevice.h"   /* for gs_deviceinitialmatrix */
26
#include "gxdevmem.h"   /* must precede gxcldev.h */
27
#include "gxcldev.h"
28
#include "gxgetbit.h"
29
#include "gxhttile.h"
30
#include "gdevplnx.h"
31
#include "gdevp14.h"
32
#include "gsmemory.h"
33
#include "gsicc_cache.h"
34
/*
35
 * We really don't like the fact that gdevprn.h is included here, since
36
 * command lists are supposed to be usable for purposes other than printer
37
 * devices; but gdev_prn_color_usage and gdev_create_buf_device are
38
 * currently only applicable to printer devices.
39
 */
40
#include "gdevprn.h"
41
#include "stream.h"
42
#include "strimpl.h"
43
44
/* #define EXTRA_OFFSET_MAP_DEBUGGING */
45
46
/* forward decl */
47
private_st_clist_icctable_entry();
48
private_st_clist_icctable();
49
50
/* ------ Band file reading stream ------ */
51
52
#ifdef DEBUG
53
/* An auxiliary table for mapping clist buffer offsets to cfile offsets. */
54
typedef struct {
55
    uint buffered;
56
    int64_t file_offset;
57
} cbuf_offset_map_elem;
58
#endif
59
60
/*
61
 * To separate banding per se from command list interpretation,
62
 * we make the command list interpreter simply read from a stream.
63
 * When we are actually doing banding, the stream filters the band file
64
 * and only passes through the commands for the current bands (or band
65
 * ranges that include a current band).
66
 */
67
typedef struct stream_band_read_state_s {
68
    stream_state_common;
69
    gx_band_page_info_t page_info;
70
    int band_first, band_last;
71
    uint left;      /* amount of data left in this run */
72
    cmd_block b_this;
73
    gs_memory_t *local_memory;
74
#ifdef DEBUG
75
    bool skip_first;
76
    cbuf_offset_map_elem *offset_map;
77
    int bytes_skipped;
78
    int offset_map_length;
79
    int offset_map_max_length;
80
    int skip_next;
81
#endif
82
} stream_band_read_state;
83
84
static int
85
s_band_read_init(stream_state * st)
86
650k
{
87
650k
    stream_band_read_state *const ss = (stream_band_read_state *) st;
88
650k
    const clist_io_procs_t *io_procs = ss->page_info.io_procs;
89
90
650k
    ss->left = 0;
91
650k
    ss->b_this.band_min = 0;
92
650k
    ss->b_this.band_max = 0;
93
650k
    ss->b_this.pos = 0;
94
650k
    return io_procs->rewind(ss->page_bfile, false, ss->page_bfname);
95
650k
}
96
97
#ifdef DEBUG
98
static int
99
s_band_read_init_offset_map(gx_device_clist_reader *crdev, stream_state * st)
100
{
101
    stream_band_read_state *const ss = (stream_band_read_state *) st;
102
103
    if (gs_debug_c('L')) {
104
        ss->offset_map_length = 0;
105
        ss->offset_map_max_length = cbuf_size + 1; /* fixme: Wanted a more accurate implementation. */
106
        ss->offset_map = (cbuf_offset_map_elem *)gs_alloc_byte_array(crdev->memory,
107
                    ss->offset_map_max_length, sizeof(*ss->offset_map), "s_band_read_init_offset_map");
108
        if (ss->offset_map == NULL)
109
            return_error(gs_error_VMerror);
110
        ss->offset_map[0].buffered = 0;
111
        ss->bytes_skipped = 0;
112
        crdev->offset_map = ss->offset_map; /* Prevent collecting it as garbage.
113
                                            Debugged with ppmraw -r300 014-09.ps . */
114
    } else {
115
        ss->offset_map_length = 0;
116
        ss->offset_map_max_length = 0;
117
        ss->offset_map = NULL;
118
        ss->bytes_skipped = 0;
119
        crdev->offset_map = NULL;
120
    }
121
    ss->skip_first = true;
122
    ss->skip_next = 0;
123
    return 0;
124
}
125
126
static void
127
s_band_read_dnit_offset_map(gx_device_clist_reader *crdev, stream_state * st)
128
{
129
    if (gs_debug_c('L')) {
130
        stream_band_read_state *const ss = (stream_band_read_state *) st;
131
132
        gs_free_object(crdev->memory, ss->offset_map, "s_band_read_dnit_offset_map");
133
        crdev->offset_map = 0;
134
    }
135
}
136
#endif
137
138
static int
139
s_band_read_process(stream_state * st, stream_cursor_read * ignore_pr,
140
                    stream_cursor_write * pw, bool last)
141
5.76M
{
142
5.76M
    stream_band_read_state *const ss = (stream_band_read_state *) st;
143
5.76M
    register byte *q = pw->ptr;
144
5.76M
    byte *wlimit = pw->limit;
145
5.76M
    clist_file_ptr cfile = ss->page_cfile;
146
5.76M
    clist_file_ptr bfile = ss->page_bfile;
147
5.76M
    uint left = ss->left;
148
5.76M
    int status = 1;
149
5.76M
    uint count;
150
5.76M
    const clist_io_procs_t *io_procs = ss->page_info.io_procs;
151
5.76M
    int64_t pos;
152
153
    /* left = number of bytes unread in the current command. */
154
    /* count = number of bytes we have room in our buffer for. */
155
45.0M
    while ((count = wlimit - q) != 0) {
156
39.9M
        int bmin, bmax;
157
        /* If there is more data to be read in the current command, then pull that in. */
158
39.9M
        if (left) {
159
22.1M
            if (count > left)
160
17.0M
                count = left;
161
#ifdef DEBUG
162
            if (gs_debug_c('L')) {
163
                if (ss->skip_next) {
164
                    /* This buffer fill is NOT going into the normal buffer. */
165
                    ss->skip_next = 0;
166
                    ss->bytes_skipped += count;
167
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
168
                    if (ss->offset_map_length != 1) {
169
                        dmlprintf(ss->local_memory, "offset_map: confused!\n");
170
                        exit(1);
171
                    }
172
#endif
173
                } else {
174
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
175
                    if (ss->offset_map[ss->offset_map_length - 1].buffered + count > cbuf_size*2) {
176
                        dmlprintf2(ss->local_memory, "Invalid update to buffered. %d %d\n",
177
                                   ss->offset_map[ss->offset_map_length - 1].buffered, count);
178
                        exit(1);
179
                    }
180
#endif
181
                    ss->offset_map[ss->offset_map_length - 1].buffered += count;
182
                }
183
            }
184
#endif
185
22.1M
            io_procs->fread_chars(q + 1, count, cfile);
186
22.1M
            if (io_procs->ferror_code(cfile) < 0) {
187
0
                status = ERRC;
188
0
                break;
189
0
            }
190
22.1M
            q += count;
191
22.1M
            left -= count;
192
22.1M
            process_interrupts(ss->local_memory);
193
22.1M
            continue;
194
22.1M
        }
195
        /* The current command is over. So find the next command in the bfile
196
         * that applies to the current band(s) and read that in. */
197
358M
        do {
198
358M
            int nread;
199
            /* If we hit eof, end! */
200
            /* Could this test be moved into the nread < sizeof() test below? */
201
358M
            if (ss->b_this.band_min == cmd_band_end &&
202
358M
                io_procs->ftell(bfile) == ss->page_bfile_end_pos) {
203
648k
                pw->ptr = q;
204
648k
                ss->left = left;
205
648k
                return EOFC;
206
648k
            }
207
208
            /* Read the next cmd_block from the bfile. Each cmd_block contains
209
             * the bands to use, and the file position of the END of the data.
210
             * We therefore want to read the data from the file position given
211
             * in the PREVIOUS record onwards, and compare to the band min/max
212
             * given there too. */
213
358M
            bmin = ss->b_this.band_min;
214
358M
            bmax = ss->b_this.band_max;
215
358M
            pos = ss->b_this.pos; /* Record where our data starts! */
216
358M
            nread = io_procs->fread_chars(&ss->b_this, sizeof(ss->b_this), bfile);
217
358M
            if (nread < sizeof(ss->b_this)) {
218
0
                DISCARD(gs_note_error(gs_error_unregistered)); /* Must not happen. */
219
0
                return ERRC;
220
0
            }
221
358M
        } while (ss->band_last < bmin || ss->band_first > bmax);
222
        /* So let's set up to read the actual command data from cfile. Seek... */
223
17.1M
        io_procs->fseek(cfile, pos, SEEK_SET, ss->page_cfname);
224
17.1M
        left = (uint) (ss->b_this.pos - pos);
225
#ifdef DEBUG
226
        if (left > 0  && gs_debug_c('L')) {
227
            if (ss->offset_map_length >= ss->offset_map_max_length) {
228
                DISCARD(gs_note_error(gs_error_unregistered)); /* Must not happen. */
229
                return ERRC;
230
            }
231
            ss->offset_map[ss->offset_map_length].file_offset = pos;
232
            ss->offset_map[ss->offset_map_length].buffered = 0;
233
            ss->offset_map_length++;
234
        }
235
#endif
236
17.1M
        if_debug5m('l', ss->local_memory,
237
17.1M
                   "[l]reading for bands (%d,%d) at bfile %"PRId64", cfile %"PRId64", length %u\n",
238
17.1M
                   bmin, bmax,
239
17.1M
                   (io_procs->ftell(bfile) - sizeof(ss->b_this)), (int64_t)pos, left);
240
17.1M
    }
241
5.11M
    pw->ptr = q;
242
5.11M
    ss->left = left;
243
5.11M
    return status;
244
5.76M
}
245
246
/* Stream template */
247
static const stream_template s_band_read_template = {
248
    &st_stream_state, s_band_read_init, s_band_read_process, 1, cbuf_size
249
};
250
251
#ifdef DEBUG
252
/* In DEBUG builds, we maintain an "offset_map" within stream_band_read_state,
253
 * that allows us to relate offsets within the buffer, to offsets within the
254
 * cfile.
255
 *
256
 * At any given point, for stream_band_read_state *ss:
257
 *    There are n = ss->offset_map_length records in the table.
258
 *    offset = 0;
259
 *    for (i = 0; i < n; i++)
260
 *       // Offset 'offset' in the buffer corresponds to ss->offset_map[i].file_offset in the file.
261
 *       offset += ss->offset_map[i].buffered
262
 *
263
 * As we pull data from the stream, we keep file_offset and buffered up to date. Note that
264
 * there are 2 cbuf_size sized buffers in play here. The cmd_buffer has one cbuf_size sized
265
 * buffer in it. Data is pulled into that from the stream, which has another cbuf_sized
266
 * buffer into it. Accordingly, 'buffered' should never be > 2*cbuf_size = 8192.
267
 *
268
 * Sometimes we will pull data out of the stream, bypassing the cmd_buffer's buffer. In this
269
 * case, we 'skip' data, and record the number of bytes skipped in ss->bytes_skipped. This
270
 * should only ever happen when we have already advanced as much as possible (i.e. when the
271
 * current offset is in the first record).
272
 */
273
274
/* Given buffer_offset (an offset within the buffer), return the number of the offset_map
275
 * record that contains it. Also fill poffset0 in with the offset of the start of that
276
 * record within the buffer. (NOTE, depending on how much of the record has already been
277
 * read, some bytes may already have been lost). */
278
static int
279
buffer_segment_index(const stream_band_read_state *ss, uint buffer_offset, uint *poffset0)
280
{
281
    uint i, offset0, offset = 0;
282
283
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
284
    dmlprintf1(ss->local_memory, "buffer_segment_index: buffer_offset=%d\n", buffer_offset);
285
    for (i = 0; i < ss->offset_map_length; i++) {
286
        dmlprintf3(ss->local_memory, " offset_map[%d].file_offset=%"PRId64" buffered=%d\n", i, ss->offset_map[i].file_offset, ss->offset_map[i].buffered);
287
    }
288
#endif
289
    for (i = 0; i < ss->offset_map_length; i++) {
290
        offset0 = offset;
291
        offset += ss->offset_map[i].buffered;
292
        if (buffer_offset < offset) {
293
            *poffset0 = offset0;
294
            return i;
295
        }
296
    }
297
    /* Now cope with the case where we've read exactly to the end of the buffer.
298
    * There might be more data still to come. */
299
    if (buffer_offset == offset) {
300
      *poffset0 = offset0;
301
      return i-1;
302
    }
303
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
304
    dmlprintf1(ss->local_memory, "buffer_segment_index fail: buffer_offset=%d not found\n", buffer_offset);
305
    exit(1);
306
#else
307
    (void)gs_note_error(gs_error_unregistered); /* Must not happen. */
308
#endif
309
    return -1;
310
}
311
312
/* Map from a buffer offset, to the offset of the corresponding byte in the
313
 * cfile. */
314
int64_t
315
clist_file_offset(const stream_state * st, uint buffer_offset)
316
{
317
    const stream_band_read_state *ss = (const stream_band_read_state *) st;
318
    uint offset0;
319
    int i = buffer_segment_index(ss, buffer_offset, &offset0);
320
321
    return ss->offset_map[i].file_offset + (uint)(buffer_offset - offset0);
322
}
323
324
void
325
top_up_offset_map(stream_state * st, const byte *buf, const byte *ptr, const byte *end)
326
{
327
    /* NOTE: The clist data are buffered in the clist reader buffer and in the
328
       internal buffer of the clist stream. Since the 1st buffer is not accessible
329
       from s_band_read_process, offset_map corresponds the union of the 2 buffers.
330
     */
331
    stream_band_read_state *const ss = (stream_band_read_state *) st;
332
    uint buffer_offset, offset0, consumed;
333
    int i;
334
335
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
336
    if (ptr < buf || end < ptr || end < buf || end > buf + cbuf_size)
337
    {
338
        dmlprintf3(ss->local_memory, "Invalid pointers for top_up_offset_map: buf=%p ptr=%p end=%p\n", buf, ptr, end);
339
    }
340
#endif
341
342
    if (!gs_debug_c('L'))
343
        return;
344
    if (ss->skip_first) {
345
        /* Work around the trick with initializing the buffer pointer with the buffer end. */
346
        ss->skip_first = false;
347
        return;
348
    }
349
    if (ptr == buf)
350
        return;
351
352
    /* We know that buf <= ptr <= end <= buf+4096, so uint is quite enough! */
353
    buffer_offset = ptr - buf;
354
    i = buffer_segment_index(ss, buffer_offset, &offset0);
355
356
    consumed = buffer_offset - offset0;
357
#ifdef EXTRA_OFFSET_MAP_DEBUGGING
358
    dmlprintf3(ss->local_memory, "offset_map: dump %d entries + %d bytes + %d skipped bytes\n", i, consumed, ss->bytes_skipped);
359
    if (ss->offset_map[i].buffered < consumed) {
360
        dmlprintf2(ss->local_memory, "Invalid update to buffered. B %d %d\n", ss->offset_map[i].buffered, consumed);
361
        exit(1);
362
    }
363
#endif
364
    ss->offset_map[i].buffered -= consumed;
365
    ss->offset_map[i].file_offset += consumed;
366
    ss->bytes_skipped = 0;
367
    if (i) {
368
        memmove(ss->offset_map, ss->offset_map + i,
369
                (ss->offset_map_length - i) * sizeof(*ss->offset_map));
370
        ss->offset_map_length -= i;
371
    }
372
}
373
374
/* This function is called when data is copied from the stream out into a separate
375
 * buffer without going through the usual clist buffers. Essentially data for the
376
 * id we are reading at buffer_offset within the buffer is skipped. */
377
void adjust_offset_map_for_skipped_data(stream_state *st, uint buffer_offset, uint skipped)
378
{
379
    uint offset0;
380
    stream_band_read_state *const ss = (stream_band_read_state *) st;
381
    int i;
382
383
    if (!gs_debug_c('L'))
384
        return;
385
386
    i = buffer_segment_index(ss, buffer_offset, &offset0);
387
388
    ss->offset_map[i].buffered -= skipped;
389
    ss->offset_map[i].file_offset += skipped;
390
}
391
392
void
393
offset_map_next_data_out_of_band(stream_state *st)
394
{
395
    stream_band_read_state *const ss = (stream_band_read_state *) st;
396
397
    if (!gs_debug_c('L'))
398
        return;
399
400
    ss->skip_next = 1;
401
}
402
#endif /* DEBUG */
403
404
/* ------ Reading/rendering ------ */
405
406
/* Calculate the raster for a chunky or planar device. */
407
static int
408
clist_plane_raster(const gx_device *dev, const gx_render_plane_t *render_plane)
409
58.8M
{
410
58.8M
    return gx_device_raster_plane(dev, render_plane);
411
58.8M
}
412
413
/* Select full-pixel rendering if required for RasterOp. */
414
void
415
clist_select_render_plane(gx_device *dev, int y, int height,
416
                          gx_render_plane_t *render_plane, int index)
417
58.8M
{
418
58.8M
    if (index >= 0) {
419
0
        gx_color_usage_t color_usage;
420
0
        int ignore_start;
421
422
0
        gdev_prn_color_usage(dev, y, height, &color_usage,  &ignore_start);
423
0
        if (color_usage.slow_rop)
424
0
            index = -1;
425
0
    }
426
58.8M
    if (index < 0)
427
58.8M
        render_plane->index = index;
428
0
    else
429
0
        gx_render_plane_init(render_plane, dev, index);
430
58.8M
}
431
432
/*
433
 * Do device setup from params stored in command list. This is only for
434
 * async rendering & assumes that the first command in every command list
435
 * is a put_params command which sets all space-related parameters to the
436
 * value they will have for the duration of that command list.
437
 */
438
int
439
clist_setup_params(gx_device *dev)
440
0
{
441
0
    gx_device_clist *cldev = (gx_device_clist *)dev;
442
0
    gx_device_clist_reader * const crdev = &cldev->reader;
443
0
    int code = clist_render_init(cldev);
444
445
0
    if (code < 0)
446
0
        return code;
447
448
0
    code = clist_playback_file_bands(playback_action_setup,
449
0
                                     crdev, &crdev->page_info, 0, 0, 0, 0, 0);
450
451
    /* put_params may have reinitialized device into a writer */
452
0
    clist_render_init(cldev);
453
454
0
    return code;
455
0
}
456
457
int
458
clist_close_writer_and_init_reader(gx_device_clist *cldev)
459
59.2M
{
460
59.2M
    gx_device_clist_reader * const crdev = &cldev->reader;
461
59.2M
    gs_memory_t *base_mem = crdev->memory->thread_safe_memory;
462
59.2M
    gs_memory_status_t mem_status;
463
59.2M
    int code = 0;
464
465
    /* Initialize for rendering if we haven't done so yet. */
466
59.2M
    if (crdev->ymin < 0) {
467
396k
        code = clist_end_page(&cldev->writer);
468
396k
        if (code < 0)
469
11
            return code;
470
396k
        code = clist_render_init(cldev);
471
396k
        if (code < 0)
472
0
            return code;
473
        /* allocate and load the color_usage_array */
474
396k
        code = clist_read_color_usage_array(crdev);
475
396k
        if (code < 0)
476
0
            return code;
477
        /* Check for and get ICC profile table */
478
396k
        code = clist_read_icctable(crdev);
479
396k
        if (code < 0)
480
0
            return code;
481
        /* Allocate the icc cache for the clist reader */
482
        /* Since we may be rendering in multiple threads, make sure the memory */
483
        /* is thread safe by using a known thread_safe memory allocator */
484
396k
        gs_memory_status(base_mem, &mem_status);
485
396k
        if (mem_status.is_thread_safe == false) {
486
0
            return_error(gs_error_VMerror);
487
0
        }
488
489
396k
        if (crdev->icc_cache_cl == NULL) {
490
108k
            code = (crdev->icc_cache_cl = gsicc_cache_new(base_mem)) == NULL ? gs_error_VMerror : code;
491
108k
        }
492
396k
    }
493
494
59.2M
    check_device_compatible_encoding((gx_device *)cldev);
495
496
59.2M
    return code;
497
59.2M
}
498
499
/* Used to find the command block information in the bfile
500
   that is related to extra information stored in a psuedo band.
501
   Currently application of this is storage of the ICC profile
502
   table, the per-band color_usage array, and the spot equivalent
503
   colors when doing overprint simulation.  We may eventually
504
   use this for storing other information like compressed images.   */
505
506
static int
507
clist_find_pseudoband(gx_device_clist_reader *crdev, int band, cmd_block *cb)
508
802k
{
509
510
802k
    gx_band_page_info_t *page_info = &(crdev->page_info);
511
802k
    clist_file_ptr bfile = page_info->bfile;
512
802k
    int64_t save_pos = page_info->bfile_end_pos;
513
802k
    int64_t start_pos;
514
802k
    int code;
515
516
802k
    if (bfile == NULL) {
517
        /* files haven't been opened yet. Do it now */
518
0
        char fmode[4];
519
520
0
        strcpy(fmode, "r");
521
0
        strncat(fmode, gp_fmode_binary_suffix, 1);
522
0
        if ((code=page_info->io_procs->fopen(page_info->cfname, fmode,
523
0
                      &page_info->cfile,
524
0
                      crdev->memory, crdev->memory, true)) < 0 ||
525
0
                      (code=page_info->io_procs->fopen(page_info->bfname, fmode,
526
0
                      &page_info->bfile,
527
0
                      crdev->memory, crdev->memory, false)) < 0) {
528
0
            return code;
529
0
        }
530
0
        bfile = page_info->bfile;
531
0
    }
532
    /* Go to the start of the last command block */
533
802k
    start_pos = page_info->bfile_end_pos - sizeof(cmd_block);
534
802k
    page_info->io_procs->fseek(bfile, start_pos, SEEK_SET, page_info->bfname);
535
15.6M
    while( 1 ) {
536
15.6M
        int read = page_info->io_procs->fread_chars(cb, sizeof(cmd_block), bfile);
537
538
15.6M
        if (read < sizeof(cmd_block))
539
0
      return -1;
540
15.6M
        if (cb->band_max == band && cb->band_min == band) {
541
401k
            page_info->io_procs->fseek(bfile, save_pos, SEEK_SET, page_info->bfname);
542
401k
            return(0);  /* Found it */
543
401k
        }
544
15.2M
        start_pos -= sizeof(cmd_block);
545
15.2M
        if (start_pos < 0) {
546
400k
           page_info->io_procs->fseek(bfile, save_pos, SEEK_SET, page_info->bfname);
547
400k
           return(-1);  /* Did not find it before getting into other stuff in normal bands */
548
400k
        }
549
14.8M
        page_info->io_procs->fseek(bfile, start_pos, SEEK_SET, page_info->bfname);
550
14.8M
    }
551
802k
}
552
553
/* A procedure to read a chunk of data from the cfile at a particular location into buff */
554
int
555
clist_read_chunk(gx_device_clist_reader *crdev, int64_t position, int size, unsigned char *buf)
556
644k
{
557
644k
    clist_file_ptr cfile = crdev->page_info.cfile;
558
644k
    int64_t save_pos;
559
560
    /* Save our current location */
561
644k
    save_pos = crdev->page_info.io_procs->ftell(cfile);
562
    /* Go to our new position */
563
644k
    crdev->page_info.io_procs->fseek(cfile, position, SEEK_SET, crdev->page_info.cfname);
564
    /* Get the data */
565
644k
    crdev->page_info.io_procs->fread_chars(buf, size, cfile);
566
    /* Restore our position */
567
644k
    crdev->page_info.io_procs->fseek(cfile, save_pos, SEEK_SET, crdev->page_info.cfname);
568
644k
    return 0;
569
644k
}
570
571
/* read the color_usage_array back from the pseudo band */
572
int
573
clist_read_color_usage_array(gx_device_clist_reader *crdev)
574
396k
{
575
396k
    int code, size_data = crdev->nbands * sizeof(gx_color_usage_t );
576
396k
    cmd_block cb;
577
578
396k
    if (crdev->color_usage_array != NULL)
579
0
        gs_free_object(crdev->memory, crdev->color_usage_array,
580
396k
                       "clist reader color_usage_array");
581
396k
    crdev->color_usage_array = (gx_color_usage_t *)gs_alloc_bytes(crdev->memory, size_data,
582
396k
                       "clist reader color_usage_array");
583
396k
    if (crdev->color_usage_array == NULL)
584
0
        return_error(gs_error_VMerror);
585
586
396k
    code = clist_find_pseudoband(crdev, crdev->nbands + COLOR_USAGE_OFFSET - 1, &cb);
587
396k
    if (code < 0)
588
0
        return code;
589
590
396k
    code = clist_read_chunk(crdev, cb.pos, size_data, (unsigned char *)crdev->color_usage_array);
591
396k
    return code;
592
396k
}
593
594
/* read the cmyk equivalent spot colors */
595
int
596
clist_read_op_equiv_cmyk_colors(gx_device_clist_reader *crdev,
597
    equivalent_cmyk_color_params *op_equiv_cmyk_colors)
598
0
{
599
0
    int code;
600
0
    cmd_block cb;
601
602
0
    code = clist_find_pseudoband(crdev, crdev->nbands + SPOT_EQUIV_COLORS - 1, &cb);
603
0
    if (code < 0)
604
0
        return code;
605
606
0
    code = clist_read_chunk(crdev, cb.pos, sizeof(equivalent_cmyk_color_params),
607
0
        (unsigned char *)op_equiv_cmyk_colors);
608
0
    return code;
609
0
}
610
611
/* Unserialize the icc table information stored in the cfile and
612
   place it in the reader device */
613
static int
614
clist_unserialize_icctable(gx_device_clist_reader *crdev, cmd_block *cb)
615
4.77k
{
616
4.77k
    clist_file_ptr cfile = crdev->page_info.cfile;
617
4.77k
    clist_icctable_t *icc_table = crdev->icc_table;
618
4.77k
    int64_t save_pos;
619
4.77k
    int number_entries, size_data;
620
4.77k
    unsigned char *buf, *buf_start;
621
4.77k
    clist_icctable_entry_t *curr_entry;
622
4.77k
    int k;
623
4.77k
    gs_memory_t *stable_mem = crdev->memory->stable_memory;
624
625
4.77k
    if ( icc_table != NULL )
626
0
        return(0);
627
4.77k
    save_pos = crdev->page_info.io_procs->ftell(cfile);
628
4.77k
    crdev->page_info.io_procs->fseek(cfile, cb->pos, SEEK_SET, crdev->page_info.cfname);
629
    /* First four bytes tell us the number of entries. */
630
4.77k
    crdev->page_info.io_procs->fread_chars(&number_entries, sizeof(number_entries), cfile);
631
    /* Allocate the space */
632
4.77k
    size_data = number_entries*sizeof(clist_icc_serial_entry_t);
633
4.77k
    buf = gs_alloc_bytes(crdev->memory, size_data, "clist_read_icctable");
634
4.77k
    buf_start = buf;
635
4.77k
    if (buf == NULL)
636
0
        return gs_rethrow(-1, "insufficient memory for icc table buffer reader");
637
    /* Get the data */
638
4.77k
    clist_read_chunk(crdev, cb->pos + 4, size_data, buf);
639
4.77k
    icc_table = gs_alloc_struct(stable_mem, clist_icctable_t,
640
4.77k
                                &st_clist_icctable, "clist_read_icctable");
641
4.77k
    if (icc_table == NULL) {
642
0
        gs_free_object(stable_mem, buf_start, "clist_read_icctable");
643
0
        return gs_rethrow(-1, "insufficient memory for icc table buffer reader");
644
0
    }
645
4.77k
    icc_table->memory = stable_mem;
646
4.77k
    icc_table->head = NULL;
647
4.77k
    icc_table->final = NULL;
648
   /* Allocate and fill each entry */
649
4.77k
    icc_table->tablesize = number_entries;
650
4.77k
    crdev->icc_table = icc_table;
651
10.7k
    for (k = 0; k < number_entries; k++) {
652
5.95k
        curr_entry = gs_alloc_struct(stable_mem, clist_icctable_entry_t,
653
5.95k
                &st_clist_icctable_entry, "clist_read_icctable");
654
5.95k
        if (curr_entry == NULL) {
655
0
            gs_free_object(stable_mem, buf_start, "clist_read_icctable");
656
0
            return gs_rethrow(-1, "insufficient memory for icc table entry");
657
0
        }
658
5.95k
        memcpy(&(curr_entry->serial_data), buf, sizeof(clist_icc_serial_entry_t));
659
5.95k
        buf += sizeof(clist_icc_serial_entry_t);
660
5.95k
        curr_entry->icc_profile = NULL;
661
5.95k
        if ( icc_table->head == NULL ) {
662
4.77k
            icc_table->head = curr_entry;
663
4.77k
            icc_table->final = curr_entry;
664
4.77k
        } else {
665
1.18k
            icc_table->final->next = curr_entry;
666
1.18k
            icc_table->final = curr_entry;
667
1.18k
        }
668
5.95k
        curr_entry->next = NULL;
669
5.95k
    }
670
4.77k
    gs_free_object(crdev->memory, buf_start, "clist_read_icctable");
671
4.77k
    crdev->page_info.io_procs->fseek(cfile, save_pos, SEEK_SET, crdev->page_info.cfname);
672
4.77k
    return 0;
673
4.77k
}
674
675
/* Get the ICC profile table information from the clist */
676
int
677
clist_read_icctable(gx_device_clist_reader *crdev)
678
405k
{
679
    /* Look for the command block of the ICC Profile. */
680
405k
    cmd_block cb;
681
405k
    int code;
682
683
    /* First get the command block which will tell us where the
684
       information is stored in the cfile */
685
405k
    code = clist_find_pseudoband(crdev, crdev->nbands + ICC_TABLE_OFFSET - 1, &cb);
686
405k
    if (code < 0)
687
400k
        return(0);   /* No ICC information */
688
    /* Unserialize the icc_table from the cfile */
689
4.77k
    code = clist_unserialize_icctable(crdev, &cb);
690
4.77k
    return(code);
691
405k
}
692
693
/* Initialize for reading. */
694
int
695
clist_render_init(gx_device_clist *dev)
696
405k
{
697
405k
    gx_device_clist_reader * const crdev = &dev->reader;
698
699
405k
    crdev->ymin = crdev->ymax = 0;
700
405k
    crdev->yplane.index = -1;
701
    /* For normal rasterizing, pages and num_pages is 1. */
702
405k
    crdev->pages = 0;
703
405k
    crdev->num_pages = 1;   /* always at least one page */
704
405k
    crdev->offset_map = NULL;
705
405k
    crdev->icc_table = NULL;
706
405k
    crdev->color_usage_array = NULL;
707
405k
    crdev->render_threads = NULL;
708
709
405k
    return 0;
710
405k
}
711
712
/* Copy a rasterized rectangle to the client, rasterizing if needed. */
713
int
714
clist_get_bits_rectangle(gx_device *dev, const gs_int_rect * prect,
715
                         gs_get_bits_params_t *params)
716
58.8M
{
717
58.8M
    gx_device_clist *cldev = (gx_device_clist *)dev;
718
58.8M
    gx_device_clist_reader *crdev = &cldev->reader;
719
58.8M
    gx_device_clist_common *cdev = (gx_device_clist_common *)dev;
720
58.8M
    gs_get_bits_options_t options = params->options;
721
58.8M
    int y = prect->p.y;
722
58.8M
    int end_y = prect->q.y;
723
58.8M
    int line_count = end_y - y;
724
58.8M
    gs_int_rect band_rect;
725
58.8M
    int lines_rasterized;
726
58.8M
    gx_device *bdev;
727
58.8M
    uint num_planes =
728
58.8M
        (options & GB_PACKING_CHUNKY ? 1 :
729
58.8M
         options & GB_PACKING_PLANAR ? dev->color_info.num_components :
730
446k
         options & GB_PACKING_BIT_PLANAR ? dev->color_info.depth :
731
0
         0 /****** NOT POSSIBLE ******/);
732
58.8M
    gx_render_plane_t render_plane;
733
58.8M
    int plane_index;
734
58.8M
    int my;
735
58.8M
    int code;
736
737
58.8M
    if (prect->p.x < 0 || prect->q.x > dev->width ||
738
58.8M
        y < 0 || end_y > dev->height
739
58.8M
        )
740
0
        return_error(gs_error_rangecheck);
741
58.8M
    if (line_count <= 0 || prect->p.x >= prect->q.x)
742
0
        return 0;
743
744
    /*
745
     * Calculate the render_plane from the params.  There are two cases:
746
     * full pixels, or a single plane.
747
     */
748
58.8M
    plane_index = -1;
749
58.8M
    if (options & GB_SELECT_PLANES) {
750
        /* Look for the one selected plane. */
751
0
        int i;
752
753
0
        for (i = 0; i < num_planes; ++i)
754
0
            if (params->data[i]) {
755
0
                if (plane_index >= 0)  /* >1 plane requested */
756
0
                    return gx_default_get_bits_rectangle(dev, prect, params);
757
0
                plane_index = i;
758
0
            }
759
0
    }
760
761
58.8M
    if (0 > (code = clist_close_writer_and_init_reader(cldev)))
762
11
        return code;
763
764
58.8M
    clist_select_render_plane(dev, y, line_count, &render_plane, plane_index);
765
58.8M
    code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
766
58.8M
                                  &bdev, cdev->target, y, &render_plane,
767
58.8M
                                  dev->memory,
768
58.8M
                                  &(crdev->color_usage_array[y/crdev->page_band_height]));
769
58.8M
    if (code < 0)
770
0
        return code;
771
58.8M
    code = clist_rasterize_lines(dev, y, line_count, bdev, &render_plane, &my);
772
58.8M
    if (code >= 0) {
773
58.8M
        lines_rasterized = min(code, line_count);
774
        /* Return as much of the rectangle as falls within the rasterized lines. */
775
58.8M
        band_rect = *prect;
776
58.8M
        band_rect.p.y = my;
777
58.8M
        band_rect.q.y = my + lines_rasterized;
778
58.8M
        code = dev_proc(bdev, get_bits_rectangle)
779
58.8M
            (bdev, &band_rect, params);
780
58.8M
    }
781
58.8M
    cdev->buf_procs.destroy_buf_device(bdev);
782
58.8M
    if (code < 0 || lines_rasterized == line_count)
783
58.8M
        return code;
784
    /*
785
     * We'll have to return the rectangle in pieces.  Force GB_RETURN_COPY
786
     * rather than GB_RETURN_POINTER, and require all subsequent pieces to
787
     * use the same values as the first piece for all of the other format
788
     * options.  If copying isn't allowed, or if there are any unread
789
     * rectangles, punt.
790
     */
791
0
    if (!(options & GB_RETURN_COPY) || code > 0)
792
0
        return gx_default_get_bits_rectangle(dev, prect, params);
793
0
    options = params->options;
794
0
    if (!(options & GB_RETURN_COPY)) {
795
        /* Redo the first piece with copying. */
796
0
        params->options = options =
797
0
            (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY;
798
0
        lines_rasterized = 0;
799
0
    }
800
0
    {
801
0
        gs_get_bits_params_t band_params;
802
0
        uint raster = gx_device_raster(bdev, true);
803
804
0
        code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
805
0
                                      &bdev, cdev->target, y, &render_plane,
806
0
                                      dev->memory,
807
0
                                      &(crdev->color_usage_array[y/crdev->page_band_height]));
808
0
        if (code < 0)
809
0
            return code;
810
0
        band_params = *params;
811
0
        while ((y += lines_rasterized) < end_y) {
812
0
            int i;
813
814
            /* Increment data pointers by lines_rasterized. */
815
0
            for (i = 0; i < num_planes; ++i)
816
0
                if (band_params.data[i])
817
0
                    band_params.data[i] += raster * lines_rasterized;
818
0
            line_count = end_y - y;
819
0
            code = clist_rasterize_lines(dev, y, line_count, bdev,
820
0
                                         &render_plane, &my);
821
0
            if (code < 0)
822
0
                break;
823
0
            lines_rasterized = min(code, line_count);
824
0
            band_rect.p.y = my;
825
0
            band_rect.q.y = my + lines_rasterized;
826
0
            code = dev_proc(bdev, get_bits_rectangle)
827
0
                (bdev, &band_rect, &band_params);
828
0
            if (code < 0)
829
0
                break;
830
0
            params->options = options = band_params.options;
831
0
            if (lines_rasterized == line_count)
832
0
                break;
833
0
        }
834
0
        cdev->buf_procs.destroy_buf_device(bdev);
835
0
    }
836
0
    return code;
837
0
}
838
839
/* Copy scan lines to the client.  This is where rendering gets done. */
840
/* Processes min(requested # lines, # lines available thru end of band) */
841
int /* returns -ve error code, or # scan lines copied */
842
clist_rasterize_lines(gx_device *dev, int y, int line_count,
843
                      gx_device *bdev, const gx_render_plane_t *render_plane,
844
                      int *pmy)
845
58.8M
{
846
58.8M
    gx_device_clist * const cldev = (gx_device_clist *)dev;
847
58.8M
    gx_device_clist_reader * const crdev = &cldev->reader;
848
58.8M
    gx_device *target = crdev->target;
849
58.8M
    uint raster = clist_plane_raster(target, render_plane);
850
58.8M
    byte *mdata = crdev->data + crdev->page_tile_cache_size;
851
58.8M
    byte *mlines = (crdev->page_line_ptrs_offset == 0 ? NULL : mdata + crdev->page_line_ptrs_offset);
852
58.8M
    int plane_index = (render_plane ? render_plane->index : -1);
853
58.8M
    int code;
854
855
    /* Render a band if necessary, and copy it incrementally. */
856
58.8M
    if (crdev->ymin < 0 || crdev->yplane.index != plane_index ||
857
58.8M
        !(y >= crdev->ymin && y < crdev->ymax)
858
58.8M
        ) {
859
641k
        int band_height = crdev->page_band_height;
860
641k
        int band = y / band_height;
861
641k
        int band_begin_line = band * band_height;
862
641k
        int band_end_line = band_begin_line + band_height;
863
641k
        int band_num_lines;
864
641k
        gs_int_rect band_rect;
865
866
641k
        if (band_end_line > dev->height)
867
24.2k
            band_end_line = dev->height;
868
        /* Clip line_count to current band */
869
641k
        if (line_count > band_end_line - y)
870
0
            line_count = band_end_line - y;
871
641k
        band_num_lines = band_end_line - band_begin_line;
872
873
641k
        if (y < 0 || y > dev->height)
874
0
            return_error(gs_error_rangecheck);
875
641k
        code = crdev->buf_procs.setup_buf_device
876
641k
            (bdev, mdata, raster, (byte **)mlines, 0, band_num_lines, band_num_lines);
877
641k
        band_rect.p.x = 0;
878
641k
        band_rect.p.y = band_begin_line;
879
641k
        band_rect.q.x = dev->width;
880
641k
        band_rect.q.y = band_end_line;
881
641k
        if (code >= 0)
882
641k
            code = clist_render_rectangle(cldev, &band_rect, bdev, render_plane,
883
641k
                                          true);
884
        /* Reset the band boundaries now, so that we don't get */
885
        /* an infinite loop. */
886
641k
        crdev->ymin = band_begin_line;
887
641k
        crdev->ymax = band_end_line;
888
641k
        crdev->offset_map = NULL;
889
641k
        if (code < 0)
890
11
            return code;
891
641k
    }
892
893
58.8M
    if (line_count > crdev->ymax - y)
894
0
        line_count = crdev->ymax - y;
895
58.8M
    code = crdev->buf_procs.setup_buf_device
896
58.8M
        (bdev, mdata, raster, (byte **)mlines, y - crdev->ymin, line_count,
897
58.8M
         crdev->ymax - crdev->ymin);
898
58.8M
    if (code < 0)
899
0
        return code;
900
901
58.8M
    *pmy = 0;
902
58.8M
    return line_count;
903
58.8M
}
904
905
/*
906
 * Render a rectangle to a client-supplied device.  There is no necessary
907
 * relationship between band boundaries and the region being rendered.
908
 */
909
int
910
clist_render_rectangle(gx_device_clist *cldev, const gs_int_rect *prect,
911
                       gx_device *bdev,
912
                       const gx_render_plane_t *render_plane, bool clear)
913
641k
{
914
641k
    gx_device_clist_reader * const crdev = &cldev->reader;
915
641k
    const gx_placed_page *ppages;
916
641k
    int num_pages = crdev->num_pages;
917
641k
    int band_height = crdev->page_band_height;
918
641k
    int band_first = prect->p.y / band_height;
919
641k
    int band_last = (prect->q.y - 1) / band_height;
920
641k
    gx_band_page_info_t *pinfo;
921
641k
    gx_band_page_info_t page_info;
922
641k
    int code = 0;
923
641k
    int i;
924
641k
    bool save_pageneutralcolor;
925
926
641k
    if (render_plane)
927
641k
        crdev->yplane = *render_plane;
928
0
    else
929
0
        crdev->yplane.index = -1;
930
641k
    if_debug2m('l', bdev->memory, "[l]rendering bands (%d,%d)\n", band_first, band_last);
931
932
641k
    ppages = crdev->pages;
933
934
    /* Before playing back the clist, make sure that the gray detection is disabled */
935
    /* so we don't slow down the rendering (primarily high level images).           */
936
641k
    save_pageneutralcolor = crdev->icc_struct->pageneutralcolor;
937
641k
    crdev->icc_struct->pageneutralcolor = false;
938
939
1.28M
    for (i = 0; i < num_pages && code >= 0; ++i) {
940
641k
        bool pdf14_needed = false;
941
641k
        int band;
942
943
641k
        if (ppages == NULL) {
944
                /*
945
                 * If we aren't rendering saved pages, do the current one.
946
                 * Note that this is the only case in which we may encounter
947
                 * a gx_saved_page with non-zero cfile or bfile.
948
                 */
949
641k
                bdev->band_offset_x = 0;
950
641k
                bdev->band_offset_y = band_first * (long)band_height;
951
641k
                pinfo = &(crdev->page_info);
952
641k
        } else {
953
0
            const gx_placed_page *ppage = &ppages[i];
954
955
            /* Store the page information. */
956
0
            page_info.cfile = page_info.bfile = NULL;
957
0
            strncpy(page_info.cfname, ppage->page->cfname, sizeof(page_info.cfname)-1);
958
0
            strncpy(page_info.bfname, ppage->page->bfname, sizeof(page_info.bfname)-1);
959
0
            page_info.io_procs = ppage->page->io_procs;
960
0
            page_info.tile_cache_size = ppage->page->tile_cache_size;
961
0
            page_info.bfile_end_pos = ppage->page->bfile_end_pos;
962
0
            page_info.band_params = ppage->page->band_params;
963
0
            page_info.line_ptrs_offset = 0;
964
0
            pinfo = &page_info;
965
966
            /*
967
             * Set the band_offset_? values in case the buffer device
968
             * needs this. Example, a device may need to adjust the
969
             * phase of the dithering based on the page position, NOT
970
             * the position within the band buffer to avoid band stitch
971
             * lines in the dither pattern. The old wtsimdi device did this
972
             *
973
             * The band_offset_x is not important for placed pages that
974
             * are nested on a 'master' page (imposition) since each
975
             * page expects to be dithered independently, but setting
976
             * this allows pages to be contiguous without a dithering
977
             * shift.
978
             *
979
             * The following sets the band_offset_? relative to the
980
             * master page.
981
             */
982
0
            bdev->band_offset_x = ppage->offset.x;
983
0
            bdev->band_offset_y = ppage->offset.y + (band_first * band_height);
984
0
        }
985
        /* if any of the requested bands need transparency, use it for all of them   */
986
        /* The pdf14_ok_to_optimize checks if the target device (bdev) is compatible */
987
        /* with the pdf14 compositor info that was written to the clist: colorspace, */
988
        /* colorspace, etc.                                                          */
989
641k
        pdf14_needed = !pdf14_ok_to_optimize(bdev);
990
973k
        for (band=band_first; !pdf14_needed && band <= band_last; band++)
991
332k
            pdf14_needed |= (crdev->color_usage_array[band].trans_bbox.p.y <=
992
332k
            crdev->color_usage_array[band].trans_bbox.q.y) ? true : false;
993
994
641k
        code = clist_playback_file_bands(pdf14_needed ?
995
416k
                                         playback_action_render : playback_action_render_no_pdf14,
996
641k
                                         crdev, pinfo,
997
641k
                                         bdev, band_first, band_last,
998
641k
                                         prect->p.x - bdev->band_offset_x,
999
641k
                                         prect->p.y);
1000
641k
    }
1001
641k
    crdev->icc_struct->pageneutralcolor = save_pageneutralcolor;  /* restore it */
1002
641k
    return code;
1003
641k
}
1004
1005
/* Playback the band file, taking the indicated action w/ its contents. */
1006
int
1007
clist_playback_file_bands(clist_playback_action action,
1008
                          gx_device_clist_reader *crdev,
1009
                          gx_band_page_info_t *page_info, gx_device *target,
1010
                          int band_first, int band_last, int x0, int y0)
1011
650k
{
1012
650k
    int code = 0;
1013
650k
    bool opened_bfile = false;
1014
650k
    bool opened_cfile = false;
1015
1016
    /* We have to pick some allocator for rendering.... */
1017
650k
    gs_memory_t *mem =crdev->memory;
1018
1019
650k
    stream_band_read_state rs;
1020
1021
    /* setup stream */
1022
650k
    s_init_state((stream_state *)&rs, &s_band_read_template,
1023
650k
                 (gs_memory_t *)0); /* Not mem, as we don't want to free rs */
1024
650k
    rs.band_first = band_first;
1025
650k
    rs.band_last = band_last;
1026
650k
    rs.page_info = *page_info;
1027
650k
    rs.local_memory = mem;
1028
1029
    /* If this is a saved page, open the files. */
1030
650k
    if (rs.page_cfile == 0) {
1031
0
        code = crdev->page_info.io_procs->fopen(rs.page_cfname,
1032
0
                           gp_fmode_rb, &rs.page_cfile, crdev->bandlist_memory,
1033
0
                           crdev->bandlist_memory, true);
1034
0
        opened_cfile = (code >= 0);
1035
0
    }
1036
650k
    if (rs.page_bfile == 0 && code >= 0) {
1037
0
        code = crdev->page_info.io_procs->fopen(rs.page_bfname,
1038
0
                           gp_fmode_rb, &rs.page_bfile, crdev->bandlist_memory,
1039
0
                           crdev->bandlist_memory, false);
1040
0
        opened_bfile = (code >= 0);
1041
0
    }
1042
650k
    if (rs.page_cfile != 0 && rs.page_bfile != 0) {
1043
650k
        stream s;
1044
650k
        byte sbuf[cbuf_size];
1045
650k
        static const stream_procs no_procs = {
1046
650k
            s_std_noavailable, s_std_noseek, s_std_read_reset,
1047
650k
            s_std_read_flush, s_std_close, s_band_read_process
1048
650k
        };
1049
1050
650k
        s_band_read_init((stream_state *)&rs);
1051
# ifdef DEBUG
1052
        s_band_read_init_offset_map(crdev, (stream_state *)&rs);
1053
# endif
1054
          /* The stream doesn't need a memory, but we'll need to access s.memory->gs_lib_ctx. */
1055
650k
        s_init(&s, mem);
1056
650k
        s_std_init(&s, sbuf, cbuf_size, &no_procs, s_mode_read);
1057
650k
        s.foreign = 1;
1058
650k
        s.state = (stream_state *)&rs;
1059
1060
650k
        code = clist_playback_band(action, crdev, &s, target, x0, y0, mem);
1061
# ifdef DEBUG
1062
        s_band_read_dnit_offset_map(crdev, (stream_state *)&rs);
1063
# endif
1064
650k
    }
1065
1066
    /* Close the files if we just opened them. */
1067
650k
    if (opened_bfile && rs.page_bfile != 0)
1068
0
        crdev->page_info.io_procs->fclose(rs.page_bfile, rs.page_bfname, false);
1069
650k
    if (opened_cfile && rs.page_cfile != 0)
1070
0
        crdev->page_info.io_procs->fclose(rs.page_cfile, rs.page_cfname, false);
1071
1072
650k
    return code;
1073
650k
}