1 /* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Command list writing utilities. */
18 
19 #include "memory_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "gp.h"
23 #include "gpcheck.h"
24 #include "gserrors.h"
25 #include "gxdevice.h"
26 #include "gxdevmem.h"		/* must precede gxcldev.h */
27 #include "gxcldev.h"
28 #include "gxclpath.h"
29 #include "gsparams.h"
30 
31 /* ---------------- Statistics ---------------- */
32 
33 #ifdef DEBUG
34 const char *const cmd_op_names[16] =
35 {cmd_op_name_strings};
36 static const char *const cmd_misc_op_names[16] =
37 {cmd_misc_op_name_strings};
38 static const char *const cmd_misc2_op_names[16] =
39 {cmd_misc2_op_name_strings};
40 static const char *const cmd_segment_op_names[16] =
41 {cmd_segment_op_name_strings};
42 static const char *const cmd_path_op_names[16] =
43 {cmd_path_op_name_strings};
44 const char *const *const cmd_sub_op_names[16] =
45 {cmd_misc_op_names, 0, 0, 0, 0, 0, 0, 0,
46  0, 0, 0, 0,
47  0, cmd_misc2_op_names, cmd_segment_op_names, cmd_path_op_names
48 };
49 struct stats_cmd_s {
50     ulong op_counts[256];
51     ulong op_sizes[256];
52     ulong tile_reset, tile_found, tile_added;
53     ulong same_band, other_band;
54 } stats_cmd;
55 extern ulong stats_cmd_diffs[5];	/* in gxclpath.c */
56 int
cmd_count_op(int op,uint size)57 cmd_count_op(int op, uint size)
58 {
59     stats_cmd.op_counts[op]++;
60     stats_cmd.op_sizes[op] += size;
61     if (gs_debug_c('L')) {
62         const char *const *sub = cmd_sub_op_names[op >> 4];
63 
64         if (sub)
65             dlprintf2(", %s(%u)\n", sub[op & 0xf], size);
66         else
67             dlprintf3(", %s %d(%u)\n", cmd_op_names[op >> 4], op & 0xf,
68                       size);
69         dflush();
70     }
71     return op;
72 }
73 void
cmd_uncount_op(int op,uint size)74 cmd_uncount_op(int op, uint size)
75 {
76     stats_cmd.op_counts[op]--;
77     stats_cmd.op_sizes[op] -= size;
78 }
79 #endif
80 
81 /* Print statistics. */
82 #ifdef DEBUG
83 void
cmd_print_stats(void)84 cmd_print_stats(void)
85 {
86     int ci, cj;
87 
88     dlprintf3("[l]counts: reset = %lu, found = %lu, added = %lu\n",
89               stats_cmd.tile_reset, stats_cmd.tile_found,
90               stats_cmd.tile_added);
91     dlprintf5("     diff 2.5 = %lu, 3 = %lu, 4 = %lu, 2 = %lu, >4 = %lu\n",
92               stats_cmd_diffs[0], stats_cmd_diffs[1], stats_cmd_diffs[2],
93               stats_cmd_diffs[3], stats_cmd_diffs[4]);
94     dlprintf2("     same_band = %lu, other_band = %lu\n",
95               stats_cmd.same_band, stats_cmd.other_band);
96     for (ci = 0; ci < 0x100; ci += 0x10) {
97         const char *const *sub = cmd_sub_op_names[ci >> 4];
98 
99         if (sub != 0) {
100             dlprintf1("[l]  %s =", cmd_op_names[ci >> 4]);
101             for (cj = ci; cj < ci + 0x10; cj += 2)
102                 dprintf6("\n\t%s = %lu(%lu), %s = %lu(%lu)",
103                          sub[cj - ci],
104                          stats_cmd.op_counts[cj], stats_cmd.op_sizes[cj],
105                          sub[cj - ci + 1],
106                    stats_cmd.op_counts[cj + 1], stats_cmd.op_sizes[cj + 1]);
107         } else {
108             ulong tcounts = 0, tsizes = 0;
109 
110             for (cj = ci; cj < ci + 0x10; cj++)
111                 tcounts += stats_cmd.op_counts[cj],
112                     tsizes += stats_cmd.op_sizes[cj];
113             dlprintf3("[l]  %s (%lu,%lu) =\n\t",
114                       cmd_op_names[ci >> 4], tcounts, tsizes);
115             for (cj = ci; cj < ci + 0x10; cj++)
116                 if (stats_cmd.op_counts[cj] == 0)
117                     dputs(" -");
118                 else
119                     dprintf2(" %lu(%lu)", stats_cmd.op_counts[cj],
120                              stats_cmd.op_sizes[cj]);
121         }
122         dputs("\n");
123     }
124 }
125 #endif /* DEBUG */
126 
127 /* ---------------- Writing utilities ---------------- */
128 
129 /* Write the commands for one band or band range. */
130 static int	/* ret 0 all ok, -ve error code, or +1 ok w/low-mem warning */
cmd_write_band(gx_device_clist_writer * cldev,int band_min,int band_max,cmd_list * pcl,gx_band_complexity_t * band_complexity,byte cmd_end)131 cmd_write_band(gx_device_clist_writer * cldev, int band_min, int band_max,
132                cmd_list * pcl, gx_band_complexity_t *band_complexity, byte cmd_end)
133 {
134     const cmd_prefix *cp = pcl->head;
135     int code_b = 0;
136     int code_c = 0;
137 
138     if (cp != 0 || cmd_end != cmd_opv_end_run) {
139         clist_file_ptr cfile = cldev->page_cfile;
140         clist_file_ptr bfile = cldev->page_bfile;
141         cmd_block cb;
142         byte end = cmd_count_op(cmd_end, 1);
143 
144         if (cfile == 0 || bfile == 0)
145             return_error(gs_error_ioerror);
146         cb.band_min = band_min;
147         cb.band_max = band_max;
148         cb.pos = cldev->page_info.io_procs->ftell(cfile);
149         clist_copy_band_complexity(&cb.band_complexity, band_complexity);
150         if_debug4('l', "[l]writing for bands (%d,%d) at %ld K %d \n",
151                   band_min, band_max, (long)cb.pos, cb.band_complexity.uses_color);
152         cldev->page_info.io_procs->fwrite_chars(&cb, sizeof(cb), bfile);
153         if (cp != 0) {
154             pcl->tail->next = 0;	/* terminate the list */
155             for (; cp != 0; cp = cp->next) {
156 #ifdef DEBUG
157                 if ((const byte *)cp < cldev->cbuf ||
158                     (const byte *)cp >= cldev->cend ||
159                     cp->size > cldev->cend - (const byte *)cp
160                     ) {
161                     lprintf1("cmd_write_band error at 0x%lx\n", (ulong) cp);
162                     return_error(gs_error_Fatal);
163                 }
164 #endif
165                 if_debug2('L',"[L]Wrote cmd id=%ld at %ld\n", cp->id,
166                     (long)cldev->page_info.io_procs->ftell(cfile));
167                 cldev->page_info.io_procs->fwrite_chars(cp + 1, cp->size, cfile);
168             }
169             pcl->head = pcl->tail = 0;
170         }
171         cldev->page_info.io_procs->fwrite_chars(&end, 1, cfile);
172         process_interrupts(cldev->memory);
173         code_b = cldev->page_info.io_procs->ferror_code(bfile);
174         code_c = cldev->page_info.io_procs->ferror_code(cfile);
175         if (code_b < 0)
176             return_error(code_b);
177         if (code_c < 0)
178             return_error(code_c);
179     }
180     return code_b | code_c;
181 }
182 
183 /* Write out the ICC profile table */
184 
185 int
cmd_write_icctable(gx_device_clist_writer * cldev,unsigned char * pbuf,int data_size)186 cmd_write_icctable(gx_device_clist_writer * cldev, unsigned char *pbuf, int data_size)
187 {
188 
189     /* Data is written out maxband + ICC_BAND_OFFSET */
190 
191     int band = cldev->band_range_max + ICC_BAND_OFFSET;
192     clist_file_ptr cfile = cldev->page_cfile;
193     clist_file_ptr bfile = cldev->page_bfile;
194     cmd_block cb;
195     int code_b, code_c;
196 
197     if (cfile == 0 || bfile == 0)
198         return_error(gs_error_ioerror);
199 
200     /* Set up the command block information that
201        is stored in the bfile.  Note complexity information
202        is filled in but not used. */
203 
204     cb.band_complexity.nontrivial_rops = false;
205     cb.band_complexity.uses_color = false;
206     cb.band_min = band;
207     cb.band_max = band;
208     cb.pos = cldev->page_info.io_procs->ftell(cfile);
209 
210     if_debug2('l', "[l]writing icc table band %d cb pos %ld\n",
211                   band, (long)cb.pos);
212 
213     cldev->page_info.io_procs->fwrite_chars(&cb, sizeof(cb), bfile);
214 
215     /* Now store the ICC table information in the cfile */
216     /* Do I need to worry about having enough room here? */
217 
218     if_debug1('l', "[l]writing icc table in cfile at %ld\n",
219             (long)cldev->page_info.io_procs->ftell(cfile));
220 
221     cldev->page_info.io_procs->fwrite_chars(pbuf, data_size, cfile);
222 
223     process_interrupts(cldev->memory);
224     code_b = cldev->page_info.io_procs->ferror_code(bfile);
225     code_c = cldev->page_info.io_procs->ferror_code(cfile);
226 
227     if (code_b < 0)
228         return_error(code_b);
229     if (code_c < 0)
230         return_error(code_c);
231 
232     return code_b | code_c;
233 
234 }
235 
236 /* Write out the buffered commands, and reset the buffer. */
237 int	/* ret 0 all-ok, -ve error code, or +1 ok w/low-mem warning */
cmd_write_buffer(gx_device_clist_writer * cldev,byte cmd_end)238 cmd_write_buffer(gx_device_clist_writer * cldev, byte cmd_end)
239 {
240     int nbands = cldev->nbands;
241     gx_clist_state *pcls;
242     int band;
243     int code = cmd_write_band(cldev, cldev->band_range_min,
244                               cldev->band_range_max,
245                               &cldev->band_range_list,
246                               NULL,
247                               cmd_opv_end_run);
248 
249     int warning = code;
250 
251     for (band = 0, pcls = cldev->states;
252          code >= 0 && band < nbands; band++, pcls++
253          ) {
254         code = cmd_write_band(cldev, band, band, &pcls->list, &pcls->band_complexity, cmd_end);
255         warning |= code;
256     }
257     /* If an error occurred, finish cleaning up the pointers. */
258     for (; band < nbands; band++, pcls++)
259         pcls->list.head = pcls->list.tail = 0;
260     cldev->cnext = cldev->cbuf;
261     cldev->ccl = 0;
262 #ifdef DEBUG
263     if (gs_debug_c('l'))
264         cmd_print_stats();
265 #endif
266     return_check_interrupt(cldev->memory, code != 0 ? code : warning);
267 }
268 
269 /*
270  * Add a command to the appropriate band list, and allocate space for its
271  * data.  Return the pointer to the data area.  If an error or (low-memory
272  * warning) occurs, set cldev->error_code and return 0.
273  */
274 #define cmd_headroom (sizeof(cmd_prefix) + ARCH_ALIGN_PTR_MOD)
275 byte *
cmd_put_list_op(gx_device_clist_writer * cldev,cmd_list * pcl,uint size)276 cmd_put_list_op(gx_device_clist_writer * cldev, cmd_list * pcl, uint size)
277 {
278     byte *dp = cldev->cnext;
279 
280     if (size + cmd_headroom > cldev->cend - dp) {
281         if ((cldev->error_code =
282              cmd_write_buffer(cldev, cmd_opv_end_run)) != 0 ||
283             (size + cmd_headroom > cldev->cend - cldev->cnext)) {
284             if (cldev->error_code < 0)
285                 cldev->error_is_retryable = 0;	/* hard error */
286             else {
287                 /* upgrade lo-mem warning into an error */
288                 if (!cldev->ignore_lo_mem_warnings)
289                     cldev->error_code = gs_note_error(gs_error_VMerror);
290                 cldev->error_is_retryable = 1;
291             }
292             return 0;
293         }
294         else
295             return cmd_put_list_op(cldev, pcl, size);
296     }
297     if (cldev->ccl == pcl) {	/* We're adding another command for the same band. */
298         /* Tack it onto the end of the previous one. */
299         cmd_count_add1(stats_cmd.same_band);
300 #ifdef DEBUG
301         if (pcl->tail->size > dp - (byte *) (pcl->tail + 1)) {
302             lprintf1("cmd_put_list_op error at 0x%lx\n", (ulong) pcl->tail);
303         }
304 #endif
305         if_debug2('L', ", to id=%ld , offset=%ld", pcl->tail->id, (long)pcl->tail->size);
306         pcl->tail->size += size;
307     } else {
308         /* Skip to an appropriate alignment boundary. */
309         /* (We assume the command buffer itself is aligned.) */
310         cmd_prefix *cp = (cmd_prefix *)
311             (dp + ((cldev->cbuf - dp) & (ARCH_ALIGN_PTR_MOD - 1)));
312 
313         cmd_count_add1(stats_cmd.other_band);
314         dp = (byte *) (cp + 1);
315         if (pcl->tail != 0) {
316 #ifdef DEBUG
317             if (pcl->tail < pcl->head ||
318                 pcl->tail->size > dp - (byte *) (pcl->tail + 1)
319                 ) {
320                 lprintf1("cmd_put_list_op error at 0x%lx\n",
321                          (ulong) pcl->tail);
322             }
323 #endif
324             pcl->tail->next = cp;
325         } else
326             pcl->head = cp;
327         pcl->tail = cp;
328         cldev->ccl = pcl;
329         cp->size = size;
330         cp->id = cldev->ins_count;
331         if_debug1('L', ", id=%ld ", cldev->ins_count);
332         cldev->ins_count++;
333     }
334     cldev->cnext = dp + size;
335     return dp;
336 }
337 
338 /* Request a space in the buffer.
339    Writes out the buffer if necessary.
340    Returns the size of available space. */
341 int
cmd_get_buffer_space(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint size)342 cmd_get_buffer_space(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
343 {
344     if (size + cmd_headroom > cldev->cend - cldev->cnext) {
345         cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run);
346         if (cldev->error_code < 0) {
347             cldev->error_is_retryable = 0;	/* hard error */
348             return cldev->error_code;
349         }
350     }
351     return cldev->cend - cldev->cnext - cmd_headroom;
352 }
353 
354 #ifdef DEBUG
355 byte *
cmd_put_op(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint size)356 cmd_put_op(gx_device_clist_writer * cldev, gx_clist_state * pcls, uint size)
357 {
358     if_debug3('L', "[L]band %d: size=%u, left=%u",
359               (int)(pcls - cldev->states),
360               size, 0);
361     return cmd_put_list_op(cldev, &pcls->list, size);
362 }
363 #endif
364 
365 /* Add a command for a range of bands. */
366 byte *
cmd_put_range_op(gx_device_clist_writer * cldev,int band_min,int band_max,uint size)367 cmd_put_range_op(gx_device_clist_writer * cldev, int band_min, int band_max,
368                  uint size)
369 {
370     if_debug4('L', "[L]band range(%d,%d): size=%u, left=%u",
371               band_min, band_max, size, 0);
372     if (cldev->ccl != 0 &&
373         (cldev->ccl != &cldev->band_range_list ||
374          band_min != cldev->band_range_min ||
375          band_max != cldev->band_range_max)
376         ) {
377         if ((cldev->error_code = cmd_write_buffer(cldev, cmd_opv_end_run)) != 0) {
378             if (cldev->error_code < 0)
379                 cldev->error_is_retryable = 0;	/* hard error */
380             else {
381                 /* upgrade lo-mem warning into an error */
382                 cldev->error_code = gs_error_VMerror;
383                 cldev->error_is_retryable = 1;
384             }
385             return 0;
386         }
387         cldev->band_range_min = band_min;
388         cldev->band_range_max = band_max;
389     }
390     return cmd_put_list_op(cldev, &cldev->band_range_list, size);
391 }
392 
393 /* Write a variable-size positive integer. */
394 int
cmd_size_w(register uint w)395 cmd_size_w(register uint w)
396 {
397     register int size = 1;
398 
399     while (w > 0x7f)
400         w >>= 7, size++;
401     return size;
402 }
403 byte *
cmd_put_w(register uint w,register byte * dp)404 cmd_put_w(register uint w, register byte * dp)
405 {
406     while (w > 0x7f)
407         *dp++ = w | 0x80, w >>= 7;
408     *dp = w;
409     return dp + 1;
410 }
411 /* Write a variable-size positive fractional. */
412 int
cmd_size_frac31(register frac31 w)413 cmd_size_frac31(register frac31 w)
414 {
415     register int size = 1;
416     register uint32_t v = w;
417 
418     while (v & 0x01FFFFFF)
419         v <<= 7, size++;
420     return size;
421 }
422 byte *
cmd_put_frac31(register frac31 w,register byte * dp)423 cmd_put_frac31(register frac31 w, register byte * dp)
424 {
425     register uint32_t v = w;
426 
427     while (v & 0x01FFFFFF)
428         *dp++ = (v >> 24) | 1, v <<= 7;
429     *dp = (v >> 24);
430     return dp + 1;
431 }
432 
433 /*
434  * This next two arrays are used for the 'delta' mode of placing a color
435  * in the clist.  These arrays are indexed by the number of bytes in the
436  * color value (the depth).
437  *
438  * Delta values are calculated by subtracting the old value for the color
439  * from the desired new value.  Then each byte of the differenece is
440  * examined.  For most bytes, if the difference fits into 4 bits (signed)
441  * then those bits are packed into the clist along with an opcode.  If
442  * the size of the color (the depth) is an odd number of bytes then instead
443  * of four bits per byte, extra bits are used for the upper three bytes
444  * of the color.  In this case, five bits are used for the first byte,
445  * six bits for the second byte, and five bits for third byte.  This
446  * maximizes the chance that the 'delta' mode can be used for placing
447  * colors in the clist.
448  */
449 /*
450  * Depending upon the compiler and user choices, the size of a gx_color_index
451  * may be 4 to 8 bytes.  We will define table entries for up to 8 bytes.
452  * This macro is being used to prevent compiler warnings if gx_color_index is
453  * only 4 bytes.
454  */
455 #define tab_entry(x) ((x) & (~((gx_color_index) 0)))
456 
457 const gx_color_index cmd_delta_offsets[] = {
458         tab_entry(0),
459         tab_entry(0),
460         tab_entry(0x0808),
461         tab_entry(0x102010),
462         tab_entry(0x08080808),
463         tab_entry(0x1020100808),
464         tab_entry(0x080808080808),
465         tab_entry(0x10201008080808),
466         tab_entry(0x0808080808080808),
467         };
468 
469 static const gx_color_index cmd_delta_masks[] = {
470         tab_entry(0),
471         tab_entry(0),
472         tab_entry(0x0f0f),
473         tab_entry(0x1f3f1f),
474         tab_entry(0x0f0f0f0f),
475         tab_entry(0x1f3f1f0f0f),
476         tab_entry(0x0f0f0f0f0f0f),
477         tab_entry(0x1f3f1f0f0f0f0f),
478         tab_entry(0x0f0f0f0f0f0f0f0f),
479         };
480 
481 #undef tab_entry
482 
483 /*
484  * There are currently only four different color "types" that can be placed
485  * into the clist.  These are called "color0", "color1", and "tile_color0",
486  * and "tile_color1".  There are separate command codes for color0 versus
487  * color1, both for the full value and delta commands - see cmd_put_color.
488  * Tile colors are preceded by a cmd_opv_set_tile_color command.
489  */
490 const clist_select_color_t
491     clist_select_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 0},
492     clist_select_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 0},
493     clist_select_tile_color0 = {cmd_op_set_color0, cmd_opv_delta_color0, 1},
494     clist_select_tile_color1 = {cmd_op_set_color1, cmd_opv_delta_color1, 1};
495 
496 /*
497  * This routine is used to place a color into the clist.  Colors, in the
498  * clist, can be specified either as by a full value or by a "delta" value.
499  *
500  * See the comments before cmd_delta_offsets[] for a description of the
501  * 'delta' mode.  The delta mode may allow for a smaller command in the clist.
502  *
503  * For the full value mode, values are sent as a cmd code plus n bytes of
504  * data.  To minimize the number of bytes, a count is made of any low order
505  * bytes which are zero.  This count is packed into the low order 4 bits
506  * of the cmd code.  The data for these bytes are not sent.
507  *
508  * The gx_no_color_index value is treated as a special case.  This is done
509  * because it is both a commonly sent value and because it may require
510  * more bytes then the other color values.
511  *
512  * Parameters:
513  *   cldev - Pointer to clist device
514  *   pcls - Pointer to clist state
515  *   select - Descriptor record for type of color being sent.  See comments
516  *       by clist_select_color_t.
517  *   color - The new color value.
518  *   pcolor - Pointer to previous color value.  (If the color value is the
519  *       same as the previous value then nothing is placed into the clist.)
520  *
521  * Returns:
522  *   Error code
523  *   clist and pcls and cldev may be updated.
524  */
525 int
cmd_put_color(gx_device_clist_writer * cldev,gx_clist_state * pcls,const clist_select_color_t * select,gx_color_index color,gx_color_index * pcolor)526 cmd_put_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
527               const clist_select_color_t * select,
528               gx_color_index color, gx_color_index * pcolor)
529 {
530     byte * dp;		/* This is manipulated by the set_cmd_put_op macro */
531     gx_color_index diff = color - *pcolor;
532     byte op, op_delta;
533     int code;
534 
535     if (diff == 0)
536         return 0;
537 
538     /* If this is a tile color then send tile color type */
539     if (select->tile_color) {
540         code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_tile_color, 1);
541         if (code < 0)
542             return code;
543     }
544     op = select->set_op;
545     op_delta = select->delta_op;
546     if (color == gx_no_color_index) {
547         /*
548          * We must handle this specially, because it may take more
549          * bytes than the color depth.
550          */
551         code = set_cmd_put_op(dp, cldev, pcls, op + cmd_no_color_index, 1);
552         if (code < 0)
553             return code;
554     } else {
555         /* Check if the "delta" mode command can be used. */
556         /* clist_color_info may be different than target device due to
557          * transparency group during clist writing phase */
558         int depth = (cldev->clist_color_info.depth <= sizeof(gx_color_index)*8 ?
559                      cldev->clist_color_info.depth : sizeof(gx_color_index)*8);
560         int num_bytes = (depth + 7) >> 3;
561         int delta_bytes = (num_bytes + 1) / 2;
562         gx_color_index delta_offset = cmd_delta_offsets[num_bytes];
563         gx_color_index delta_mask = cmd_delta_masks[num_bytes];
564         gx_color_index delta = (diff + delta_offset) & delta_mask;
565         bool use_delta = (color == (*pcolor + delta - delta_offset));
566         int bytes_dropped = 0;
567         gx_color_index data = color;
568 
569         /*
570          * If we use the full value mode, we do not send low order bytes
571          * which are zero. Determine how many low order bytes are zero.
572          */
573         if (color == 0) {
574             bytes_dropped = num_bytes;
575         }
576         else  {
577             while ((data & 0xff) == 0) {
578                 bytes_dropped++;
579                 data >>= 8;
580             }
581         }
582         /* Now send one of the two command forms */
583         if (use_delta && delta_bytes < (num_bytes - bytes_dropped)) {
584             code = set_cmd_put_op(dp, cldev, pcls,
585                                         op_delta, delta_bytes + 1);
586             if (code < 0)
587                 return code;
588             /*
589              * If we have an odd number of bytes then use extra bits for
590              * the high order three bytes of the color.
591              */
592             if ((num_bytes >= 3) && (num_bytes & 1)) {
593                 data = delta >> ((num_bytes - 3) * 8);
594                 dp[delta_bytes--] = (byte)(((data >> 13) & 0xf8) + ((data >> 11) & 0x07));
595                 dp[delta_bytes--] = (byte)(((data >> 3) & 0xe0) + (data & 0x1f));
596             }
597             for(; delta_bytes>0; delta_bytes--) {
598                 dp[delta_bytes] = (byte)((delta >> 4) + delta);
599                 delta >>= 16;
600             }
601         }
602         else {
603             num_bytes -= bytes_dropped;
604             code = set_cmd_put_op(dp, cldev, pcls,
605                                 (byte)(op + bytes_dropped), num_bytes + 1);
606             if (code < 0)
607                 return code;
608             for(; num_bytes>0; num_bytes--) {
609                 dp[num_bytes] = (byte)data;
610                 data >>= 8;
611             }
612         }
613     }
614     *pcolor = color;
615     return 0;
616 }
617 
618 /* Put out a command to set the tile colors. */
619 int
cmd_set_tile_colors(gx_device_clist_writer * cldev,gx_clist_state * pcls,gx_color_index color0,gx_color_index color1)620 cmd_set_tile_colors(gx_device_clist_writer * cldev, gx_clist_state * pcls,
621                     gx_color_index color0, gx_color_index color1)
622 {
623     int code = 0;
624 
625     if (color0 != pcls->tile_colors[0]) {
626         code = cmd_put_color(cldev, pcls,
627                              &clist_select_tile_color0,
628                              color0, &pcls->tile_colors[0]);
629         if (code != 0)
630             return code;
631     }
632     if (color1 != pcls->tile_colors[1])
633         code = cmd_put_color(cldev, pcls,
634                              &clist_select_tile_color1,
635                              color1, &pcls->tile_colors[1]);
636     return code;
637 }
638 
639 /* Put out a command to set the tile phase. */
640 int
cmd_set_tile_phase_generic(gx_device_clist_writer * cldev,gx_clist_state * pcls,int px,int py,bool all_bands)641 cmd_set_tile_phase_generic(gx_device_clist_writer * cldev, gx_clist_state * pcls,
642                    int px, int py, bool all_bands)
643 {
644     int pcsize;
645     byte *dp;
646     int code;
647 
648     pcsize = 1 + cmd_size2w(px, py);
649     if (all_bands)
650         code = set_cmd_put_all_op(dp, cldev, (byte)cmd_opv_set_tile_phase, pcsize);
651     else
652         code = set_cmd_put_op(dp, cldev, pcls, (byte)cmd_opv_set_tile_phase, pcsize);
653     if (code < 0)
654         return code;
655     ++dp;
656     pcls->tile_phase.x = px;
657     pcls->tile_phase.y = py;
658     cmd_putxy(pcls->tile_phase, dp);
659     return 0;
660 }
661 
662 int
cmd_set_tile_phase(gx_device_clist_writer * cldev,gx_clist_state * pcls,int px,int py)663 cmd_set_tile_phase(gx_device_clist_writer * cldev, gx_clist_state * pcls,
664                    int px, int py)
665 {
666     return cmd_set_tile_phase_generic(cldev, pcls, px, py, false);
667 }
668 
669 /* Write a command to enable or disable the logical operation. */
670 int
cmd_put_enable_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,int enable)671 cmd_put_enable_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
672                    int enable)
673 {
674     byte *dp;
675     int code = set_cmd_put_op(dp, cldev, pcls,
676                               (byte)(enable ? cmd_opv_enable_lop :
677                                      cmd_opv_disable_lop),
678                               1);
679 
680     if (code < 0)
681         return code;
682     pcls->lop_enabled = enable;
683     return 0;
684 }
685 
686 /* Write a command to enable or disable clipping. */
687 /* This routine is only called if the path extensions are included. */
688 int
cmd_put_enable_clip(gx_device_clist_writer * cldev,gx_clist_state * pcls,int enable)689 cmd_put_enable_clip(gx_device_clist_writer * cldev, gx_clist_state * pcls,
690                     int enable)
691 {
692     byte *dp;
693     int code = set_cmd_put_op(dp, cldev, pcls,
694                               (byte)(enable ? cmd_opv_enable_clip :
695                                      cmd_opv_disable_clip),
696                               1);
697 
698     if (code < 0)
699         return code;
700     pcls->clip_enabled = enable;
701     return 0;
702 }
703 
704 /* Write a command to set the logical operation. */
705 int
cmd_set_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,gs_logical_operation_t lop)706 cmd_set_lop(gx_device_clist_writer * cldev, gx_clist_state * pcls,
707             gs_logical_operation_t lop)
708 {
709     byte *dp;
710     uint lop_msb = lop >> 6;
711     int code = set_cmd_put_op(dp, cldev, pcls,
712                               cmd_opv_set_misc, 2 + cmd_size_w(lop_msb));
713 
714     if (code < 0)
715         return code;
716     dp[1] = cmd_set_misc_lop + (lop & 0x3f);
717     cmd_put_w(lop_msb, dp + 2);
718     pcls->lop = lop;
719     return 0;
720 }
721 
722 /* Disable (if default) or enable the logical operation, setting it if */
723 /* needed. */
724 int
cmd_update_lop(gx_device_clist_writer * cldev,gx_clist_state * pcls,gs_logical_operation_t lop)725 cmd_update_lop(gx_device_clist_writer *cldev, gx_clist_state *pcls,
726                gs_logical_operation_t lop)
727 {
728     int code;
729 
730     if (lop == lop_default)
731         return cmd_disable_lop(cldev, pcls);
732     code = cmd_set_lop(cldev, pcls, lop);
733     if (code < 0)
734         return code;
735     return cmd_enable_lop(cldev, pcls);
736 }
737 
738 /* Write a parameter list */
739 int	/* ret 0 all ok, -ve error */
cmd_put_params(gx_device_clist_writer * cldev,gs_param_list * param_list)740 cmd_put_params(gx_device_clist_writer *cldev,
741                gs_param_list *param_list) /* NB open for READ */
742 {
743     byte *dp;
744     int code;
745     byte local_buf[512];	/* arbitrary */
746     int param_length;
747 
748     /* Get serialized list's length + try to get it into local var if it fits. */
749     param_length = code =
750         gs_param_list_serialize(param_list, local_buf, sizeof(local_buf));
751     if (param_length > 0) {
752         /* Get cmd buffer space for serialized */
753         code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend,
754                                   2 + sizeof(unsigned) + param_length);
755         if (code < 0)
756             return code;
757 
758         /* write param list to cmd list: needs to all fit in cmd buffer */
759         if_debug1('l', "[l]put_params, length=%d\n", param_length);
760         dp[1] = cmd_opv_ext_put_params;
761         dp += 2;
762         memcpy(dp, &param_length, sizeof(unsigned));
763         dp += sizeof(unsigned);
764         if (param_length > sizeof(local_buf)) {
765             int old_param_length = param_length;
766 
767             param_length = code =
768                 gs_param_list_serialize(param_list, dp, old_param_length);
769             if (param_length >= 0)
770                 code = (old_param_length != param_length ?
771                         gs_note_error(gs_error_unknownerror) : 0);
772             if (code < 0) {
773                 /* error serializing: back out by writing a 0-length parm list */
774                 memset(dp - sizeof(unsigned), 0, sizeof(unsigned));
775                 cmd_shorten_list_op(cldev, &cldev->band_range_list,
776                                     old_param_length);
777             }
778         } else
779             memcpy(dp, local_buf, param_length);	    /* did this when computing length */
780     }
781     return code;
782 }
783 
784 /* Initialize CCITTFax filters. */
785 static void
clist_cf_init(stream_CF_state * ss,int width)786 clist_cf_init(stream_CF_state *ss, int width)
787 {
788     ss->K = -1;
789     ss->Columns = width;
790 #if 0 /* Disabled due to a crash with ppmraw -r216 c327.bin :
791          the decoding filter overruns in 1 byte.
792        */
793     ss->EndOfBlock = false;
794 #else
795     ss->EndOfBlock = true;
796 #endif
797     ss->BlackIs1 = true;
798     ss->DecodedByteAlign = align_bitmap_mod;
799 }
800 void
clist_cfe_init(stream_CFE_state * ss,int width,gs_memory_t * mem)801 clist_cfe_init(stream_CFE_state *ss, int width, gs_memory_t *mem)
802 {
803     s_init_state((stream_state *)ss, &s_CFE_template, mem);
804     s_CFE_set_defaults_inline(ss);
805     clist_cf_init((stream_CF_state *)ss, width);
806     s_CFE_template.init((stream_state *)(ss));
807 }
808 void
clist_cfd_init(stream_CFD_state * ss,int width,int height,gs_memory_t * mem)809 clist_cfd_init(stream_CFD_state *ss, int width, int height, gs_memory_t *mem)
810 {
811     s_init_state((stream_state *)ss, &s_CFD_template, mem);
812     s_CFD_template.set_defaults((stream_state *)ss);
813     clist_cf_init((stream_CF_state *)ss, width);
814     ss->Rows = height;
815     s_CFD_template.init((stream_state *)(ss));
816 }
817 
818 /* Initialize RunLength filters. */
819 void
clist_rle_init(stream_RLE_state * ss)820 clist_rle_init(stream_RLE_state *ss)
821 {
822     s_init_state((stream_state *)ss, &s_RLE_template, (gs_memory_t *)0);
823     s_RLE_set_defaults_inline(ss);
824     s_RLE_init_inline(ss);
825 }
826 void
clist_rld_init(stream_RLD_state * ss)827 clist_rld_init(stream_RLD_state *ss)
828 {
829     s_init_state((stream_state *)ss, &s_RLD_template, (gs_memory_t *)0);
830     s_RLD_set_defaults_inline(ss);
831     s_RLD_init_inline(ss);
832 }
833 
834 /* Read a transformation matrix. */
835 const byte *
cmd_read_matrix(gs_matrix * pmat,const byte * cbp)836 cmd_read_matrix(gs_matrix * pmat, const byte * cbp)
837 {
838     stream s;
839 
840     s_init(&s, NULL);
841     sread_string(&s, cbp, 1 + sizeof(*pmat));
842     sget_matrix(&s, pmat);
843     return cbp + stell(&s);
844 }
845