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 /* Color operators */
18 #include "memory_.h"
19 #include "math_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "dstack.h"	/* for systemdict */
23 #include "estack.h"
24 #include "ialloc.h"
25 #include "igstate.h"
26 #include "iutil.h"
27 #include "store.h"
28 #include "gscolor.h"	/* for gs_setgray and gs_setrgbcolor */
29 #include "gscsepr.h"	/* For declarartion of Separation functions */
30 #include "gscdevn.h"	/* For declarartion of DeviceN functions */
31 #include "gscpixel.h"	/* For declarartion of DevicePixel functions */
32 #include "gxfixed.h"
33 #include "gxmatrix.h"
34 #include "gzstate.h"
35 #include "gxdcolor.h"		/* for gxpcolor.h */
36 #include "gxdevice.h"
37 #include "gxdevmem.h"		/* for gxpcolor.h */
38 #include "gxcmap.h"
39 #include "gxcspace.h"
40 #include "gxcolor2.h"
41 #include "gxpcolor.h"
42 #include "idict.h"
43 #include "icolor.h"
44 #include "idparam.h"
45 #include "iname.h"
46 #include "iutil.h"
47 #include "ifunc.h"	/* For declaration of buildfunction */
48 #include "icsmap.h"
49 #include "ifunc.h"
50 #include "zht2.h"
51 #include "zcolor.h"	/* For the PS_colour_space_t structure */
52 #include "zcie.h"	/* For CIE space function declarations */
53 #include "zicc.h"	/* For declaration of seticc */
54 #include "gscspace.h"   /* Needed for checking if current pgs colorspace is CIE */
55 #include "iddict.h"	/* for idict_put_string */
56 #include "zfrsd.h"      /* for make_rss() */
57 
58 /* imported from gsht.c */
59 extern  void    gx_set_effective_transfer(gs_state *);
60 
61 /* Essential forward declarations */
62 static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth);
63 static int setcolorspace_cont(i_ctx_t *i_ctx_p);
64 static int setcolor_cont(i_ctx_t *i_ctx_p);
65 
66 /* define the number of stack slots needed for zcolor_remap_one */
67 const int   zcolor_remap_one_ostack = 4;
68 const int   zcolor_remap_one_estack = 3;
69 
70 /* utility to test whether a Pattern instance uses a base space */
71 static inline bool
pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)72 pattern_instance_uses_base_space(const gs_pattern_instance_t * pinst)
73 {
74     return pinst->type->procs.uses_base_space(
75                    pinst->type->procs.get_pattern(pinst) );
76 }
77 
78 /*
79  *  -   currentcolor   <param1>  ...  <paramN>
80  *
81  * Return the current color. <paramN> may be a dictionary or a null
82  * object, if the current color space is a pattern color space. The
83  * other parameters will be numeric.
84  *
85  * Note that the results of this operator differ slightly from those of
86  * most currentcolor implementations. If a color component value is
87  * integral (e.g.: 0, 1), it will be pushed on the stack as an integer.
88  * Most currentcolor implementations, including the earlier
89  * implementation in Ghostscript, would push real objects for all
90  * color spaces except indexed color space. The approach taken here is
91  * equally legitimate, and avoids special handling of indexed color
92  * spaces.
93  */
94 static int
zcurrentcolor(i_ctx_t * i_ctx_p)95 zcurrentcolor(i_ctx_t * i_ctx_p)
96 {
97     os_ptr                  op = osp;
98     const gs_color_space *  pcs = gs_currentcolorspace(igs);
99     const gs_client_color * pcc = gs_currentcolor(igs);
100     int                     i, n = cs_num_components(pcs);
101     bool                    push_pattern = n < 0;
102 
103     /* check for pattern */
104     if (push_pattern) {
105         gs_pattern_instance_t * pinst = pcc->pattern;
106 
107         if (pinst == 0 || !pattern_instance_uses_base_space(pinst))
108             n = 1;
109         else
110             n = -n;
111     }
112 
113     /* check for sufficient space on the stack */
114     push(n);
115     op -= n - 1;
116 
117     /* push the numeric operands, if any */
118     if (push_pattern)
119         --n;
120     for (i = 0; i < n; i++, op++) {
121         float   rval = pcc->paint.values[i];
122         int     ival = (int)rval;
123 
124         /* the following handles indexed color spaces */
125         if (rval == ival && pcs->type->index == gs_color_space_index_Indexed)
126             make_int(op, ival);
127         else
128             make_real(op, rval);
129     }
130 
131     /* push the pattern dictionary or null object, if appropriate */
132     if (push_pattern)
133         *op = istate->pattern[0];
134 
135     return 0;
136 }
137 
138 /*
139  *  -   .currentcolorspace   <array>
140  *
141  * Return the current color space. Unlike the prior implementation, the
142  * istate->color_space.array field will now always have a legitimate
143  * (array) value.
144  */
145 static int
zcurrentcolorspace(i_ctx_t * i_ctx_p)146 zcurrentcolorspace(i_ctx_t * i_ctx_p)
147 {
148     os_ptr  op = osp;   /* required by "push" macro */
149     int code;
150     ref namestr,stref;
151     byte *body;
152 
153     /* Adobe applications expect that the Device spaces (DeviceGray
154      * DeviceRGB and DeviceCMYK) will always return the same array.
155      * Not merely the same content but the same actual array. To do
156      * this we define the arrays at startup (see gs_cspace.ps), and
157      * recover them here by executing PostScript.
158      */
159     if (r_has_type(&istate->colorspace[0].array, t_name)) {
160         name_string_ref(imemory, &istate->colorspace[0].array, &namestr);
161         if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceGray", 10)) {
162             body = ialloc_string(32, "string");
163             if (body == 0)
164                 return_error(e_VMerror);
165             memcpy(body, "systemdict /DeviceGray_array get", 32);
166             make_string(&stref, a_all | icurrent_space, 32, body);
167         } else {
168             if (r_size(&namestr) == 9 && !memcmp(namestr.value.bytes, "DeviceRGB", 9)) {
169                 body = ialloc_string(31, "string");
170                 if (body == 0)
171                     return_error(e_VMerror);
172                 memcpy(body, "systemdict /DeviceRGB_array get", 31);
173                 make_string(&stref, a_all | icurrent_space, 31, body);
174             } else {
175                 if (r_size(&namestr) == 10 && !memcmp(namestr.value.bytes, "DeviceCMYK", 10)) {
176                     body = ialloc_string(32, "string");
177                     if (body == 0)
178                         return_error(e_VMerror);
179                     memcpy(body, "systemdict /DeviceCMYK_array get", 32);
180                     make_string(&stref, a_all | icurrent_space, 32, body);
181                 } else {
182                     /* Not one of the Device spaces, but still just a name. Give
183                      * up and return the name on the stack.
184                      */
185                     push(1);
186                     code = ialloc_ref_array(op, a_all, 1, "currentcolorspace");
187                     if (code < 0)
188                         return code;
189                     refset_null(op->value.refs, 1);
190                     ref_assign_old(op, op->value.refs,
191                                    &istate->colorspace[0].array,
192                                    "currentcolorspace");
193                     return 0;
194                 }
195             }
196         }
197         r_set_attrs(&stref, a_executable);
198         esp++;
199         ref_assign(esp, &stref);
200         return o_push_estack;
201     } else {
202         /* If the space isn't a simple name, then we don't need any special
203          * action and can simply use it.
204          */
205         push(1);
206         *op = istate->colorspace[0].array;
207     }
208     return 0;
209 }
210 
211 /*
212  *  -   .getuseciecolor   <bool>
213  *
214  * Return the current setting of the use_cie_color graphic state parameter,
215  * which tracks the UseCIEColor page device parameter. This parameter may be
216  * read (via this operator) at all language leves, but may only be set (via
217  * the .setuseciecolor operator; see zcolor3.c) only in language level 3.
218  *
219  * We handle this parameter separately from the page device primarily for
220  * performance reasons (the parameter may be queried frequently), but as a
221  * side effect achieve proper behavior relative to the language level. The
222  * interpreter is always initialized with this parameter set to false, and
223  * it can only be updated (via setpagedevice) in language level 3.
224  */
225 static int
zgetuseciecolor(i_ctx_t * i_ctx_p)226 zgetuseciecolor(i_ctx_t * i_ctx_p)
227 {
228     os_ptr  op = osp;
229 
230     push(1);
231     *op = istate->use_cie_color;
232     return 0;
233 }
234 
235 /* Clean up when unwinding the stack on an error.  (No action needed.) */
236 static int
colour_cleanup(i_ctx_t * i_ctx_p)237 colour_cleanup(i_ctx_t *i_ctx_p)
238 {
239     return 0;
240 }
241 
242 /*
243  *  <param1>  ...  <paramN>   setcolor   -
244  *
245  * Set the current color. All of the parameters except the topmost (paramN) are
246  * numbers; the topmost (and possibly only) entry may be pattern dictionary or
247  * a null object.
248  *
249  * The use of one operator to set both patterns and "normal" colors is
250  * consistent with Adobe's documentation, but primarily reflects the use of
251  * gs_setcolor for both purposes in the graphic library. An alternate
252  * implementation would use a .setpattern operator, which would interface with
253  * gs_setpattern.
254  *
255  * This operator is hidden by a pseudo-operator of the same name, so it will
256  * only be invoked under controlled situations. Hence, it does no operand
257  * checking.
258  */
259 static int
zsetcolor(i_ctx_t * i_ctx_p)260 zsetcolor(i_ctx_t * i_ctx_p)
261 {
262     os_ptr                  op = osp;
263     es_ptr ep = esp;
264     const gs_color_space *  pcs = gs_currentcolorspace(igs);
265     gs_client_color         cc;
266     int                     n_comps, n_numeric_comps, num_offset = 0, code, depth;
267     bool                    is_ptype2 = 0;
268     PS_colour_space_t *space;
269 
270     /* initialize the client color pattern pointer for GC */
271     cc.pattern = 0;
272 
273     /* check for a pattern color space */
274     if ((n_comps = cs_num_components(pcs)) < 0) {
275         n_comps = -n_comps;
276         if (r_has_type(op, t_dictionary)) {
277             ref     *pImpl, pPatInst;
278             int     ptype;
279 
280             code = dict_find_string(op, "Implementation", &pImpl);
281             if (code < 0)
282                 return code;
283             code = array_get(imemory, pImpl, 0, &pPatInst);
284             if (code < 0)
285                 return code;
286             cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
287             n_numeric_comps = ( pattern_instance_uses_base_space(cc.pattern)
288                                   ? n_comps - 1
289                                   : 0 );
290             (void)dict_int_param(op, "PatternType", 1, 2, 1, &ptype);
291             is_ptype2 = ptype == 2;
292         } else
293             n_numeric_comps = 0;
294         num_offset = 1;
295     } else
296         n_numeric_comps = n_comps;
297 
298     /* gather the numeric operands */
299     code = float_params(op - num_offset, n_numeric_comps, cc.paint.values);
300     if (code < 0)
301         return code;
302 
303     code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &space);
304     if (code < 0)
305         return code;
306     if (space->validatecomponents) {
307         code = space->validatecomponents(i_ctx_p,
308                                          &istate->colorspace[0].array,
309                                          cc.paint.values, n_numeric_comps);
310         if (code < 0)
311             return code;
312     }
313 
314     /* pass the color to the graphic library */
315     if ((code = gs_setcolor(igs, &cc)) >= 0) {
316 
317         if (n_comps > n_numeric_comps) {
318             istate->pattern[0] = *op;      /* save pattern dict or null */
319             n_comps = n_numeric_comps + 1;
320         }
321     }
322 
323     /* Check the color spaces, to see if we need to run any tint transform
324      * procedures. Some Adobe applications *eg Photoshop) expect that the
325      * tint transform will be run and use this to set up duotone DeviceN
326      * spaces.
327      */
328     code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
329     if (code < 0)
330         return code;
331     /* Set up for the continuation procedure which will do the work */
332     /* Make sure the exec stack has enough space */
333     check_estack(5);
334     /* A place holder for data potentially used by transform functions */
335     ep = esp += 1;
336     make_int(ep, 0);
337     /* Store the 'depth' of the space returned during checking above */
338     ep = esp += 1;
339     make_int(ep, 0);
340     /* Store the 'stage' of processing (initially 0) */
341     ep = esp += 1;
342     make_int(ep, 0);
343     /* Store a pointer to the color space stored on the operand stack
344      * as the stack may grow unpredictably making further access
345      * to the space difficult
346      */
347     ep = esp += 1;
348     *ep = istate->colorspace[0].array;
349     /* Finally, the actual continuation routine */
350     push_op_estack(setcolor_cont);
351     return o_push_estack;
352 }
353 
354 /* This is used to detect color space changes due
355    to the changing of UseCIEColor during transparency
356    soft mask processing */
357 
name_is_device_color(char * cs_name)358 static bool name_is_device_color( char *cs_name )
359 {
360 
361     return( strcmp(cs_name, "DeviceGray") == 0 ||
362             strcmp(cs_name, "DeviceRGB")  == 0 ||
363             strcmp(cs_name, "DeviceCMYK") == 0);
364 
365 }
366 
367 /*
368  * Given two color space arrays, attempts to determine if they are the
369  * same space by comparing their contents recursively. For some spaces,
370  * especially CIE based color spaces, it can significantly improve
371  * performance if the same space is frequently re-used.
372  */
is_same_colorspace(i_ctx_t * i_ctx_p,ref * space1,ref * space2,bool isCIE)373 static int is_same_colorspace(i_ctx_t * i_ctx_p, ref *space1, ref *space2, bool isCIE)
374 {
375     PS_colour_space_t *oldcspace = 0, *newcspace = 0;
376     ref oldspace, *poldspace = &oldspace, newspace, *pnewspace = &newspace;
377     int code, CIESubst;
378 
379     /* Silence compiler warnings */
380     oldspace.tas.type_attrs = 0;
381     oldspace.tas.type_attrs = 0;
382 
383     ref_assign(pnewspace, space1);
384     ref_assign(poldspace, space2);
385 
386     do {
387         if (r_type(poldspace) != r_type(pnewspace))
388             return 0;
389 
390         code = get_space_object(i_ctx_p, poldspace, &oldcspace);
391         if (code < 0)
392             return 0;
393 
394         code = get_space_object(i_ctx_p, pnewspace, &newcspace);
395         if (code < 0)
396             return 0;
397 
398         /* Check the two color space types are the same
399          * (Indexed, Separation, DeviceCMYK etc).
400          */
401         if (strcmp(oldcspace->name, newcspace->name) != 0)
402             return 0;
403 
404         /* Call the space-specific comparison routine */
405         if (!oldcspace->compareproc(i_ctx_p, poldspace, pnewspace))
406             return 0;
407 
408         /* See if current space is CIE based (which could happen
409            if UseCIE had been true previously), but UseCIE is false
410            and incoming space is device based.  This can occur
411            when we are now processing a soft mask, which should not
412            use the UseCIEColor option.
413 
414            Need to detect this case at both transitions
415 
416             Device Color UseCIEColor true
417             Soft mask
418                     Device color UseCIEColor false
419             Soft mask
420             Device color UseCIEColor true
421             */
422 
423         if ( name_is_device_color(newcspace->name) ){
424             if ( gs_color_space_is_CIE(gs_currentcolorspace_inline(i_ctx_p->pgs)) ){
425                 if ( !isCIE ) return 0; /*  The color spaces will be different */
426             } else {
427                 if ( isCIE ) return 0; /*  The color spaces will be different */
428             }
429         }
430 
431         /* The current space is OK, if there is no alternate, then that's
432          * good enough.
433          */
434         if (!oldcspace->alternateproc)
435             break;
436 
437         /* Otherwise, retrieve the alternate space for each, and continue
438          * round the loop, checking those.
439          */
440         code = oldcspace->alternateproc(i_ctx_p, poldspace, &poldspace, &CIESubst);
441         if (code < 0)
442             return 0;
443 
444         code = newcspace->alternateproc(i_ctx_p, pnewspace, &pnewspace, &CIESubst);
445         if (code < 0)
446             return 0;
447     }
448     while(1);
449 
450     return 1;
451 }
452 
453 /*
454  *  <array>   setcolorspace   -
455  *
456  * Set the nominal color space. This color space will be pushd by the
457  * currentcolorspace operator, but is not directly used to pass color
458  * space information to the graphic library.
459  *
460  */
461 static int
zsetcolorspace(i_ctx_t * i_ctx_p)462 zsetcolorspace(i_ctx_t * i_ctx_p)
463 {
464     os_ptr  op = osp;
465     es_ptr ep = esp;
466     int code, depth;
467     bool is_CIE;
468 
469     /* Make sure we have an operand... */
470     check_op(1);
471     /* Check its either a name (base space) or an array */
472     if (!r_has_type(op, t_name))
473         if (!r_is_array(op))
474             return_error(e_typecheck);
475 
476     code = validate_spaces(i_ctx_p, op, &depth);
477     if (code < 0)
478         return code;
479 
480     is_CIE = istate->use_cie_color.value.boolval;
481 
482     /* See if its the same as the current space */
483     if (is_same_colorspace(i_ctx_p, op, &istate->colorspace[0].array, is_CIE)) {
484         PS_colour_space_t *cspace;
485 
486         /* Even if its the same space, we still need to set the correct
487          * initial color value.
488          */
489         code = get_space_object(i_ctx_p, &istate->colorspace[0].array, &cspace);
490         if (code < 0)
491             return 0;
492         if (cspace->initialcolorproc) {
493             cspace->initialcolorproc(i_ctx_p, &istate->colorspace[0].array);
494         }
495         /* Pop the space off the stack */
496         pop(1);
497         return 0;
498     }
499     /* Set up for the continuation procedure which will do the work */
500     /* Make sure the exec stack has enough space */
501     check_estack(5);
502     /* Store the initial value of CIE substitution (not substituting) */
503     ep = esp += 1;
504     make_int(ep, 0);
505     /* Store the 'depth' of the space returned during checking above */
506     ep = esp += 1;
507     make_int(ep, depth);
508     /* Store the 'stage' of processing (initially 0) */
509     ep = esp += 1;
510     make_int(ep, 0);
511     /* Store a pointer to the color space stored on the operand stack
512      * as the stack may grow unpredictably making further access
513      * to the space difficult
514      */
515     ep = esp += 1;
516     *ep = *op;
517     /* Finally, the actual continuation routine */
518     push_op_estack(setcolorspace_cont);
519     return o_push_estack;
520 }
521 
522 /*
523  * A special version of the setcolorspace operation above. This sets the
524  * CIE substitution flag to true before starting, which prevents any further
525  * CIE substitution taking place.
526  */
527 static int
setcolorspace_nosubst(i_ctx_t * i_ctx_p)528 setcolorspace_nosubst(i_ctx_t * i_ctx_p)
529 {
530     os_ptr  op = osp;
531     es_ptr ep = esp;
532     int code, depth;
533 
534     /* Make sure we have an operand... */
535     check_op(1);
536     /* Check its either a name (base space) or an array */
537     if (!r_has_type(op, t_name))
538         if (!r_is_array(op))
539             return_error(e_typecheck);
540 
541     code = validate_spaces(i_ctx_p, op, &depth);
542     if (code < 0)
543         return code;
544 
545     /* Set up for the continuation procedure which will do the work */
546     /* Make sure the exec stack has enough space */
547     check_estack(5);
548     /* Store the initial value of CIE substitution (substituting) */
549     ep = esp += 1;
550     make_int(ep, 1);
551     /* Store the 'depth' of the space returned during checking above */
552     ep = esp += 1;
553     make_int(ep, depth);
554     /* Store the 'stage' of processing (initially 0) */
555     ep = esp += 1;
556     make_int(ep, 0);
557     /* Store a pointer to the color space stored on the operand stack
558      * as the stack may grow unpredictably making further access
559      * to the space difficult
560      */
561     ep = esp += 1;
562     *ep = *op;
563     /* Finally, the actual continuation routine */
564     push_op_estack(setcolorspace_cont);
565     return o_push_estack;
566 }
567 
568 /*
569  *  <name> .includecolorspace -
570  *
571  * See the comment for gs_includecolorspace in gscolor2.c .
572  */
573 static int
zincludecolorspace(i_ctx_t * i_ctx_p)574 zincludecolorspace(i_ctx_t * i_ctx_p)
575 {
576     os_ptr  op = osp;
577     ref nsref;
578     int code;
579 
580     check_type(*op, t_name);
581     name_string_ref(imemory, op, &nsref);
582     code =  gs_includecolorspace(igs, nsref.value.const_bytes, r_size(&nsref));
583     if (!code)
584         pop(1);
585     return code;
586 }
587 
588 /*  -   currenttransfer   <proc> */
589 static int
zcurrenttransfer(i_ctx_t * i_ctx_p)590 zcurrenttransfer(i_ctx_t *i_ctx_p)
591 {
592     os_ptr  op = osp;
593 
594     push(1);
595     *op = istate->transfer_procs.gray;
596     return 0;
597 }
598 
599 /*
600  *  -   processcolors   <int>  -
601  *
602  * Note: this is an undocumented operator that is not supported
603  * in Level 2.
604  */
605 static int
zprocesscolors(i_ctx_t * i_ctx_p)606 zprocesscolors(i_ctx_t * i_ctx_p)
607 {
608     os_ptr  op = osp;
609 
610     push(1);
611     make_int(op, gs_currentdevice(igs)->color_info.num_components);
612     return 0;
613 }
614 
615 /* <proc> settransfer - */
616 static int
zsettransfer(i_ctx_t * i_ctx_p)617 zsettransfer(i_ctx_t * i_ctx_p)
618 {
619     os_ptr  op = osp;
620     int     code;
621 
622     check_proc(*op);
623     check_ostack(zcolor_remap_one_ostack - 1);
624     check_estack(1 + zcolor_remap_one_estack);
625     istate->transfer_procs.red =
626         istate->transfer_procs.green =
627         istate->transfer_procs.blue =
628         istate->transfer_procs.gray = *op;
629     if ((code = gs_settransfer_remap(igs, gs_mapped_transfer, false)) < 0)
630         return code;
631     push_op_estack(zcolor_reset_transfer);
632     pop(1);
633     return zcolor_remap_one( i_ctx_p,
634                              &istate->transfer_procs.gray,
635                              igs->set_transfer.gray,
636                              igs,
637                              zcolor_remap_one_finish );
638 }
639 
640 /*
641  * Internal routines
642  */
643 
644 /*
645  * Prepare to remap one color component (also used for black generation
646  * and undercolor removal). Use the 'for' operator to gather the values.
647  * The caller must have done the necessary check_ostack and check_estack.
648  */
649 int
zcolor_remap_one(i_ctx_t * i_ctx_p,const ref * pproc,gx_transfer_map * pmap,const gs_state * pgs,op_proc_t finish_proc)650 zcolor_remap_one(
651     i_ctx_t *           i_ctx_p,
652     const ref *         pproc,
653     gx_transfer_map *   pmap,
654     const gs_state *    pgs,
655     op_proc_t           finish_proc )
656 {
657     os_ptr              op;
658 
659     /*
660      * Detect the identity function, which is a common value for one or
661      * more of these functions.
662      */
663     if (r_size(pproc) == 0) {
664         gx_set_identity_transfer(pmap);
665         /*
666          * Even though we don't actually push anything on the e-stack, all
667          * clients do, so we return o_push_estack in this case.  This is
668          * needed so that clients' finishing procedures will get run.
669          */
670         return o_push_estack;
671     }
672     op = osp += 4;
673     make_real(op - 3, 0);
674     make_int(op - 2, transfer_map_size - 1);
675     make_real(op - 1, 1);
676     *op = *pproc;
677     ++esp;
678     make_struct(esp, imemory_space((gs_ref_memory_t *) pgs->memory),
679                 pmap);
680     push_op_estack(finish_proc);
681     push_op_estack(zfor_samples);
682     return o_push_estack;
683 }
684 
685 /* Store the result of remapping a component. */
686 static int
zcolor_remap_one_store(i_ctx_t * i_ctx_p,floatp min_value)687 zcolor_remap_one_store(i_ctx_t *i_ctx_p, floatp min_value)
688 {
689     int i;
690     gx_transfer_map *pmap = r_ptr(esp, gx_transfer_map);
691 
692     if (ref_stack_count(&o_stack) < transfer_map_size)
693         return_error(e_stackunderflow);
694     for (i = 0; i < transfer_map_size; i++) {
695         double v;
696         int code =
697             real_param(ref_stack_index(&o_stack, transfer_map_size - 1 - i),
698                        &v);
699 
700         if (code < 0)
701             return code;
702         pmap->values[i] =
703             (v < min_value ? float2frac(min_value) :
704              v >= 1.0 ? frac_1 :
705              float2frac(v));
706     }
707     ref_stack_pop(&o_stack, transfer_map_size);
708     esp--;			/* pop pointer to transfer map */
709     return o_pop_estack;
710 }
711 int
zcolor_remap_one_finish(i_ctx_t * i_ctx_p)712 zcolor_remap_one_finish(i_ctx_t *i_ctx_p)
713 {
714     return zcolor_remap_one_store(i_ctx_p, 0.0);
715 }
716 int
zcolor_remap_one_signed_finish(i_ctx_t * i_ctx_p)717 zcolor_remap_one_signed_finish(i_ctx_t *i_ctx_p)
718 {
719     return zcolor_remap_one_store(i_ctx_p, -1.0);
720 }
721 
722 /* Finally, reset the effective transfer functions and */
723 /* invalidate the current color. */
724 int
zcolor_reset_transfer(i_ctx_t * i_ctx_p)725 zcolor_reset_transfer(i_ctx_t *i_ctx_p)
726 {
727     gx_set_effective_transfer(igs);
728     return zcolor_remap_color(i_ctx_p);
729 }
730 int
zcolor_remap_color(i_ctx_t * i_ctx_p)731 zcolor_remap_color(i_ctx_t *i_ctx_p)
732 {
733     /* Remap both colors. This should never hurt. */
734     gs_swapcolors(igs);
735     gx_unset_dev_color(igs);
736     gs_swapcolors(igs);
737     gx_unset_dev_color(igs);
738     return 0;
739 }
740 
741 /*
742  * <param1> ... <paramN> .color_test <param1> ... <paramN>
743  *
744  * encode and decode color to allow mapping to be tested.
745  */
746 static int
zcolor_test(i_ctx_t * i_ctx_p)747 zcolor_test(i_ctx_t *i_ctx_p)
748 {
749     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
750     gx_device *dev = gs_currentdevice(igs);
751     int ncomp = dev->color_info.num_components;
752     gx_color_index color;
753     os_ptr op = osp - (ncomp-1);
754     int i;
755     if (ref_stack_count(&o_stack) < ncomp)
756         return_error(e_stackunderflow);
757     for (i = 0; i < ncomp; i++) {
758         if (r_has_type(op+i, t_real))
759             cv[i] = (gx_color_value)
760                 (op[i].value.realval * gx_max_color_value);
761         else if (r_has_type(op+i, t_integer))
762             cv[i] = (gx_color_value)
763                 (op[i].value.intval * gx_max_color_value);
764         else
765             return_error(e_typecheck);
766     }
767     color = (*dev_proc(dev, encode_color)) (dev, cv);
768     (*dev_proc(dev, decode_color)) (dev, color, cv);
769     for (i = 0; i < ncomp; i++)
770         make_real(op+i, (float)cv[i] / (float)gx_max_color_value);
771     return 0;
772 }
773 
774 /*
775  * <levels> .color_test_all <value0> ... <valueN>
776  *
777  * Test encode/decode color procedures for a range of values.
778  * Return value with the worst error in a single component.
779  */
780 static int
zcolor_test_all(i_ctx_t * i_ctx_p)781 zcolor_test_all(i_ctx_t *i_ctx_p)
782 {
783     os_ptr                  op = osp;
784     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
785     gx_color_value cvout[GX_DEVICE_COLOR_MAX_COMPONENTS];
786     gx_color_value cvbad[GX_DEVICE_COLOR_MAX_COMPONENTS];
787     int counter[GX_DEVICE_COLOR_MAX_COMPONENTS];
788     gx_device *dev = gs_currentdevice(igs);
789     int ncomp = dev->color_info.num_components;
790     int steps;
791     int maxerror = 0;
792     int err;
793     int acceptable_error;
794     int linsep = dev->color_info.separable_and_linear == GX_CINFO_SEP_LIN;
795     int linsepfailed = 0;
796     int lsmaxerror = 0;
797     gx_color_index color, lscolor;
798     int i, j, k;
799     int finished = 0;
800 
801     if (ncomp == 1)
802         acceptable_error = gx_max_color_value / dev->color_info.max_gray + 1;
803     else
804         acceptable_error = gx_max_color_value / dev->color_info.max_color + 1;
805 
806     if (ref_stack_count(&o_stack) < 1)
807         return_error(e_stackunderflow);
808     if (!r_has_type(&osp[0], t_integer))
809         return_error(e_typecheck);
810     steps = osp[0].value.intval;
811     for (i = 0; i < ncomp; i++) {
812         counter[i] = 0;
813         cvbad[i] = 0;
814     }
815 
816     dprintf1("Number of components = %d\n", ncomp);
817     dprintf1("Depth = %d\n", dev->color_info.depth);
818     dprintf2("max_gray = %d   dither_grays = %d\n",
819         dev->color_info.max_gray, dev->color_info.dither_grays);
820     dprintf2("max_color = %d   dither_colors = %d\n",
821         dev->color_info.max_color, dev->color_info.dither_colors);
822     dprintf1("polarity = %s\n",
823       dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE ? "Additive" :
824       dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE ?"Subtractive":
825       "Unknown");
826     /* Indicate color index value with all colorants = zero */
827     for (i = 0; i < ncomp; i++)
828         cv[i] = 0;
829     color = (*dev_proc(dev, encode_color)) (dev, cv);
830     if (sizeof(color) <= sizeof(ulong))
831         dprintf1("Zero color index:  %8lx\n", (ulong)color);
832     else
833         dprintf2("Zero color index:  %8lx%08lx\n",
834             (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color);
835 
836     dprintf1("separable_and_linear = %s\n",
837       linsep == GX_CINFO_SEP_LIN_NONE ? "No" :
838       linsep == GX_CINFO_SEP_LIN ? "Yes" :
839       "Unknown");
840     if (dev->color_info.gray_index == GX_CINFO_COMP_INDEX_UNKNOWN)
841         dprintf("gray_index is unknown\n");
842     else
843         dprintf1("gray_index = %d\n", dev->color_info.gray_index);
844     if (linsep) {
845         dprintf(" Shift     Mask  Bits\n");
846         for (i = 0; i < ncomp; i++) {
847             dprintf3(" %5d %8x  %4d\n",
848                 (int)(dev->color_info.comp_shift[i]),
849                 (int)(dev->color_info.comp_mask[i]),
850                 (int)(dev->color_info.comp_bits[i]));
851         }
852     }
853 
854     while (!finished) {
855         for (j = 0; j <= steps; j++) {
856             for (i = 0; i < ncomp; i++)
857                 cv[i] = counter[i] * gx_max_color_value / steps;
858             color = (*dev_proc(dev, encode_color)) (dev, cv);
859             if (linsep) {
860                 /* Derive it the other way */
861                 lscolor = gx_default_encode_color(dev, cv);
862                 if ((color != lscolor) && (linsepfailed < 5)) {
863                     linsepfailed++;
864                     dprintf("Failed separable_and_linear for");
865                     for (i = 0; i < ncomp; i++)
866                         dprintf1(" %d", cv[i]);
867                     dprintf("\n");
868                     dprintf2("encode_color=%x  gx_default_encode_color=%x\n",
869                         (int)color, (int)lscolor);
870                 }
871             }
872             (*dev_proc(dev, decode_color)) (dev, color, cvout);
873             for (i = 0; i < ncomp; i++) {
874                 err = (int)cvout[i] - (int)cv[i];
875                 if (err < 0)
876                     err = -err;
877                 if (err > maxerror) {
878                     maxerror = err;
879                     for (k=0; k < ncomp; k++)
880                         cvbad[k] = cv[k];
881                 }
882             }
883             if (linsep) {
884                 gx_default_decode_color(dev, color, cvout);
885                 for (i = 0; i < ncomp; i++) {
886                     err = (int)cvout[i] - (int)cv[i];
887                     if (err < 0)
888                         err = -err;
889                     if (err > lsmaxerror) {
890                         lsmaxerror = err;
891                     }
892                 }
893             }
894             counter[0] += 1;
895         }
896         counter[0] = 0;
897         i = 1;
898         while (i < ncomp) {
899             counter[i] += 1;
900             if (counter[i] > steps) {
901                 counter[i] = 0;
902                 i++;
903             }
904             else
905                 break;
906         }
907         if (i >= ncomp)
908             finished = 1;
909     }
910 
911     dprintf2("Maximum error %g %s\n",
912         (float)maxerror / (float)gx_max_color_value,
913         maxerror <= acceptable_error ? "is Ok" :
914         maxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
915 
916     if (linsep)
917       dprintf2("Maximum linear_and_separable error %g %s\n",
918         (float)lsmaxerror / (float)gx_max_color_value,
919         lsmaxerror <= acceptable_error ? "is Ok" :
920         lsmaxerror <= 3*acceptable_error/2 ? "is POOR" : "FAILED");
921 
922     /* push worst value */
923     push(ncomp-1);
924     op -= ncomp - 1;
925     for (i = 0; i < ncomp; i++)
926         make_real(op+i, (float)cvbad[i] / (float)gx_max_color_value);
927 
928     return 0;
929 }
930 
931 /* Convert between RGB and HSB colors, using the hexcone approach (see
932  * Rogers, David, "Procedureal Elements For Computer Graphics",
933  * (McGraw-Hill, 1985), pp. 402 - 3).
934  *
935  * The rgb ==> hsb calculation is:
936  *
937  *   br = max(r, g, b)
938  *
939  *   if (br == 0)
940  *       h = 0, s = 0;
941  *   else {
942  *       v = min(r, g, b)
943  *       diff = br - v;
944  *       sat = diff / br;
945  *       if (r == br)
946  *           h = (g - b) / (6 * diff) + (b > g ? 1 : 0);
947  *       else if (g == br)
948  *           h = 1/3 + (b - r) / (6 * diff);
949  *       else
950  *           h = 2/3 + (r - g) / (6 * diff);
951  *   }
952  */
rgb2hsb(float * RGB)953 static int rgb2hsb(float *RGB)
954 {
955     float HSB[3], v, diff;
956     int i, j=0;
957 
958     v = 1.0;
959     for (i=0;i<3;i++)
960         HSB[i] = 0.0;
961     for (i=0;i<3;i++) {
962         if (RGB[i] > HSB[2]) {
963             HSB[2] = RGB[i];
964             j = i;
965         }
966         if (RGB[i] < v)
967             v = RGB[i];
968     }
969     if (HSB[2] != 0) {
970         diff = HSB[2] - v;
971         HSB[1] = diff / HSB[2];
972         switch (j) {
973             case 0 : /* R == Brightness */
974                 /* diff can only be zero if r == br, so we need to make sure here we
975                  * don't divide by zero
976                  */
977                 if (diff)
978                     HSB[0] = ((RGB[1] - RGB[2]) / (6.0 * diff)) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
979                 else
980                     HSB[0] = (RGB[1] - RGB[2]) + (RGB[2] > RGB[1] ? 1.0 : 0.0);
981                 break;
982             case 1 : /* G == Brightness */
983                 HSB[0] = (1.0 / 3.0) + (RGB[2] - RGB[0]) / (6.0 * diff);
984                 break;
985             case 2 : /* B == Brightness */
986                 HSB[0] = (2.0 / 3.0) + (RGB[0] - RGB[1]) / (6.0 * diff);
987                 break;
988         }
989     }
990     for (i=0;i<3;i++) {
991         if (HSB[i] < 0)
992             HSB[i] = 0;
993         if (RGB[i] > 1)
994             HSB[i] = 1;
995         RGB[i] = HSB[i];
996     }
997     return 0;
998 }
999 /* The hsb ==> rgb conversion is:
1000  *
1001  *    mn = (1 - s) * br, md = 6 * s * br;
1002  *
1003  *    switch ((int)floor(6 * h)) {
1004  *      case 0:   %% r >= g >= b
1005  *        r = br;
1006  *        g = mn + h * md;
1007  *        b = mn;
1008  *        break;
1009  *
1010  *      case 1:  %% g >= r >= b
1011  *        r = mn + md * (1/3 - h);
1012  *        g = br;
1013  *        b = mn;
1014  *        break;
1015  *
1016  *      case 2:  %% g >= b >= r
1017  *        r = mn;
1018  *        g = br;
1019  *        b = mn + (h - 1/3) * md;
1020  *        break;
1021  *
1022  *      case 3:  %% b >= g >= r
1023  *        r = mn;
1024  *        g = mn + (2/3 - h) * md;
1025  *        b = br;
1026  *        break;
1027  *
1028  *      case 4:  %% b >= r >= g
1029  *        r = mn + (h - 2/3) * md;
1030  *        g = mn;
1031  *        b = br;
1032  *        break;
1033  *
1034  *      case 5:  %% r >= b >= g
1035  *        r = br;
1036  *        g = mn;
1037  *        b = mn + (1 - h) * md;
1038  *        break;
1039  *
1040  *      case 6:  %% We have wrapped around the hexcone.  Thus this case is
1041  *      		   the same as case 0 with h = 0
1042  *        h = 0;
1043  *        r = br;
1044  *        g = mn + h * md = mn;
1045  *        b = mn;
1046  *        break;
1047  *    }
1048  */
hsb2rgb(float * HSB)1049 static int hsb2rgb(float *HSB)
1050 {
1051     float RGB[3], mn, md;
1052     int i;
1053 
1054     mn = (1.0 - HSB[1]) * HSB[2];
1055     md = 6.0 * HSB[1] * HSB[2];
1056 
1057     switch ((int)floor(6.0 * HSB[0])) {
1058         case 6:
1059             HSB[0] = (float)0;
1060         default: /* Shuts up compiler warning about RGB being uninited */
1061         case 0:
1062             RGB[0] = HSB[2];
1063             RGB[1] = mn + (HSB[0] * md);
1064             RGB[2] = mn;
1065             break;
1066         case 1:
1067             RGB[0] = mn + (md * ((1.0 / 3.0) - HSB[0]));
1068             RGB[1] = HSB[2];
1069             RGB[2] = mn;
1070             break;
1071         case 2:
1072             RGB[0] = mn;
1073             RGB[1] = HSB[2];
1074             RGB[2] = mn + ((HSB[0] - (1.0 / 3.0)) * md);
1075             break;
1076         case 3:
1077             RGB[0] = mn;
1078             RGB[1] = mn + (((2.0 / 3.0f) - HSB[0]) * md);
1079             RGB[2] = HSB[2];
1080             break;
1081         case 4:
1082             RGB[0] = mn + ((HSB[0] - (2.0 / 3.0)) * md);
1083             RGB[1] = mn;
1084             RGB[2] = HSB[2];
1085             break;
1086         case 5:
1087             RGB[0] = HSB[2];
1088             RGB[1] = mn;
1089             RGB[2] = mn + ((1.0 - HSB[0]) * md);
1090             break;
1091     }
1092     for (i=0;i<3;i++) {
1093         if (RGB[i] < 0)
1094             RGB[i] = 0;
1095         if (RGB[i] > 1)
1096             RGB[i] = 1;
1097         HSB[i] = RGB[i];
1098     }
1099     return 0;
1100 }
1101 
1102 /* The routines for handling colors and color spaces, moved from
1103  * PostScript to C, start here.
1104  */
1105 
1106 /* DeviceGray */
setgrayspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1107 static int setgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1108 {
1109     os_ptr op = osp;
1110     gs_color_space  *pcs;
1111     int code=0;
1112     ref stref;
1113 
1114     do {
1115         switch (*stage) {
1116             case 0:
1117                 if (istate->use_cie_color.value.boolval && !CIESubst) {
1118                     byte *body;
1119                     ref *nosubst;
1120 
1121                     code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1122                     if (code < 0)
1123                         return code;
1124                     if (!r_has_type(nosubst, t_boolean))
1125                         return_error(e_typecheck);
1126                     if (nosubst->value.boolval) {
1127                         *stage = 4;
1128                         *cont = 1;
1129                         body = ialloc_string(32, "string");
1130                         if (body == 0)
1131                             return_error(e_VMerror);
1132                         memcpy(body, "/DefaultGray ..nosubstdevicetest",32);
1133                         make_string(&stref, a_all | icurrent_space, 32, body);
1134                         r_set_attrs(&stref, a_executable);
1135                         esp++;
1136                         ref_assign(esp, &stref);
1137                         return o_push_estack;
1138                     } else {
1139                         *stage = 2;
1140                         *cont = 1;
1141                         body = ialloc_string(47, "string");
1142                         if (body == 0)
1143                             return_error(e_VMerror);
1144                         memcpy(body, "{/DefaultGray /ColorSpace findresource} stopped",47);
1145                         make_string(&stref, a_all | icurrent_space, 47, body);
1146                         r_set_attrs(&stref, a_executable);
1147                         esp++;
1148                         ref_assign(esp, &stref);
1149                         return o_push_estack;
1150                     }
1151                     break;
1152                 }
1153                 /* fall through */
1154             case 1:
1155                 pcs = gs_cspace_new_DeviceGray(imemory);
1156                 if (pcs == NULL)
1157                     return_error(e_VMerror);
1158                 code = gs_setcolorspace(igs, pcs);
1159                 if (code >= 0) {
1160                     gs_client_color *pcc = gs_currentcolor_inline(igs);
1161 
1162                     cs_adjust_color_count(igs, -1); /* not strictly necessary */
1163                     pcc->paint.values[0] = (0);
1164                     pcc->pattern = 0;		/* for GC */
1165                     gx_unset_dev_color(igs);
1166                 }
1167                 rc_decrement_only_cs(pcs, "zsetdevcspace");
1168                 *cont = 0;
1169                 *stage = 0;
1170                 break;
1171             case 2:
1172                 if (!r_has_type(op, t_boolean))
1173                     return_error(e_typecheck);
1174                 if (op->value.boolval) {
1175                     /* Failed to find the /DefaultGray CSA, so give up and
1176                      * just use DeviceGray
1177                      */
1178                     pop(1);
1179                     *stage = 1;
1180                     break;
1181                 }
1182                 pop(1);
1183                 *cont = 1;
1184                 *stage = 3;
1185                 code = setcolorspace_nosubst(i_ctx_p);
1186                 if (code != 0)
1187                     return code;
1188                 break;
1189             case 3:
1190                 /* We end up here after setting the DefaultGray space
1191                  * We've finished setting the gray color space, so we
1192                  * just exit now
1193                  */
1194                 *cont = 0;
1195                 *stage = 0;
1196                 break;
1197             case 4:
1198                 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1199                  * is also true. We will have a boolean on the stack, if its true
1200                  * then we need to set the space (also on the stack), invoke
1201                  * .includecolorspace, and set /DeviceGray, otherwise we just need
1202                  * to set DeviceGray. See gs_cspace.ps.
1203                  */
1204                 if (!r_has_type(op, t_boolean))
1205                     return_error(e_typecheck);
1206                 pop(1);
1207                 *stage = 1;
1208                 *cont = 1;
1209                 if (op->value.boolval) {
1210                     *stage = 5;
1211                     code = setcolorspace_nosubst(i_ctx_p);
1212                     if (code != 0)
1213                         return code;
1214                 }
1215                 break;
1216             case 5:
1217                 /* After stage 4 above, if we had to set a color space, we come
1218                  * here. Now we need to use .includecolorspace to register the space
1219                  * with any high-level devices which want it.
1220                  */
1221                 *stage = 1;
1222                 *cont = 1;
1223                 code = zincludecolorspace(i_ctx_p);
1224                 if (code != 0)
1225                     return code;
1226                 break;
1227         }
1228     } while (*stage);
1229     return code;
1230 }
graydomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1231 static int graydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1232 {
1233     ptr[0] = 0;
1234     ptr[1] = 1;
1235     return 0;
1236 }
grayrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1237 static int grayrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1238 {
1239     ptr[0] = 0;
1240     ptr[1] = 1;
1241     return 0;
1242 }
1243 /* This routine converts a Gray value into its equivalent in a different
1244  * device space, required by currentgray, currentrgb, currenthsb and
1245  * currentcmyk. The actual color value will have been processed through
1246  * the tint transform(s) of the parent space(s) until it reaches a device
1247  * space. This converts that final value into the requested space.
1248  */
graybasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1249 static int graybasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1250 {
1251     os_ptr op = osp;
1252     float Gray, RGB[3];
1253 
1254     *cont = 0;
1255     *stage = 0;
1256     check_op(1);
1257     if (!r_has_type(op, t_integer)) {
1258         if (r_has_type(op, t_real)) {
1259             Gray = op->value.realval;
1260         } else
1261             return_error(e_typecheck);
1262     } else
1263         Gray = (float)op->value.intval;
1264 
1265     if (Gray < 0 || Gray > 1)
1266         return_error(e_rangecheck);
1267 
1268     switch (base) {
1269         case 0:
1270             /* Requested space is DeviceGray, just use the value */
1271             make_real(op, Gray);
1272             break;
1273         case 1:
1274             /* Requested space is HSB */
1275         case 2:
1276             /* Requested space is RGB, set all the components
1277              * to the gray value
1278              */
1279             push(2);
1280             RGB[0] = RGB[1] = RGB[2] = Gray;
1281             if (base == 1)
1282                 /* If the requested space is HSB, convert the RGB to HSB */
1283                 rgb2hsb((float *)&RGB);
1284             make_real(&op[-2], RGB[0]);
1285             make_real(&op[-1], RGB[1]);
1286             make_real(op, RGB[2]);
1287             break;
1288         case 3:
1289             /* Requested space is CMYK, use the gray value to set the
1290              * black channel.
1291              */
1292             push(3);
1293             make_real(&op[-3], (float)0);
1294             make_real(&op[-2], (float)0);
1295             make_real(&op[-1], (float)0);
1296             make_real(op, (float)1.0 - Gray);
1297             break;
1298         default:
1299             return_error(e_undefined);
1300     }
1301     return 0;
1302 }
grayvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1303 static int grayvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1304 {
1305     os_ptr op = osp;
1306 
1307     if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1308         return_error(e_typecheck);
1309 
1310     if (num_comps < 1)
1311         return_error(e_stackunderflow);
1312 
1313     if (*values > 1.0)
1314         *values = 1.0;
1315 
1316     if ( *values < 0.0)
1317         *values = 0.0;
1318 
1319     return 0;
1320 }
grayinitialproc(i_ctx_t * i_ctx_p,ref * space)1321 static int grayinitialproc(i_ctx_t *i_ctx_p, ref *space)
1322 {
1323     gs_client_color cc;
1324 
1325     cc.pattern = 0x00;
1326     cc.paint.values[0] = 0;
1327     return gs_setcolor(igs, &cc);
1328 }
1329 
1330 /* DeviceRGB */
setrgbspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1331 static int setrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1332 {
1333     os_ptr op = osp;
1334     gs_color_space  *pcs;
1335     int code=0;
1336     ref stref;
1337 
1338     do {
1339         switch (*stage) {
1340             case 0:
1341                 if (istate->use_cie_color.value.boolval && !CIESubst) {
1342                     byte *body;
1343                     ref *nosubst;
1344 
1345                     code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1346                     if (code < 0)
1347                         return code;
1348                     if (!r_has_type(nosubst, t_boolean))
1349                         return_error(e_typecheck);
1350                     if (nosubst->value.boolval) {
1351                         *stage = 4;
1352                         *cont = 1;
1353                         body = ialloc_string(31, "string");
1354                         if (body == 0)
1355                             return_error(e_VMerror);
1356                         memcpy(body, "/DefaultRGB ..nosubstdevicetest",31);
1357                         make_string(&stref, a_all | icurrent_space, 31, body);
1358                         r_set_attrs(&stref, a_executable);
1359                         esp++;
1360                         ref_assign(esp, &stref);
1361                         return o_push_estack;
1362                     } else {
1363                         *stage = 2;
1364                         *cont = 1;
1365                         body = ialloc_string(46, "string");
1366                         if (body == 0)
1367                             return_error(e_VMerror);
1368                         memcpy(body, "{/DefaultRGB /ColorSpace findresource} stopped", 46);
1369                         make_string(&stref, a_all | icurrent_space, 46, body);
1370                         r_set_attrs(&stref, a_executable);
1371                         esp++;
1372                         ref_assign(esp, &stref);
1373                         return o_push_estack;
1374                     }
1375                 }
1376                 /* fall through */
1377             case 1:
1378                 pcs = gs_cspace_new_DeviceRGB(imemory);
1379                 if (pcs == NULL)
1380                     return_error(e_VMerror);
1381                 code = gs_setcolorspace(igs, pcs);
1382                 if (code >= 0) {
1383                     gs_client_color *pcc = gs_currentcolor_inline(igs);
1384 
1385                     cs_adjust_color_count(igs, -1); /* not strictly necessary */
1386                     pcc->paint.values[0] = 0;
1387                     pcc->paint.values[1] = 0;
1388                     pcc->paint.values[2] = 0;
1389                     pcc->pattern = 0;		/* for GC */
1390                     gx_unset_dev_color(igs);
1391                 }
1392                 rc_decrement_only_cs(pcs, "zsetdevcspace");
1393                 *cont = 0;
1394                 *stage = 0;
1395                 break;
1396             case 2:
1397                 if (!r_has_type(op, t_boolean))
1398                     return_error(e_typecheck);
1399                 if (op->value.boolval) {
1400                     /* Failed to find the /DefaultRGB CSA, so give up and
1401                      * just use DeviceRGB
1402                      */
1403                     pop(1);
1404                     *stage = 1;
1405                     break;
1406                 }
1407                 pop(1);
1408                 *stage = 3;
1409                 code = setcolorspace_nosubst(i_ctx_p);
1410                 if (code != 0)
1411                     return code;
1412                 break;
1413             case 3:
1414                 /* We end up here after setting the DefaultGray CIE space
1415                  * We've finished setting the gray color space, so we
1416                  * just exit now
1417                  */
1418                 *cont = 0;
1419                 *stage = 0;
1420                 break;
1421             case 4:
1422                 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1423                  * is also true. We will have a boolean on the stack, if its true
1424                  * then we need to set the space (also on the stack), invoke
1425                  * .includecolorspace, and set /DeviceGray, otherwise we just need
1426                  * to set DeviceGray. See gs-cspace.ps.
1427                  */
1428                 if (!r_has_type(op, t_boolean))
1429                     return_error(e_typecheck);
1430                 pop(1);
1431                 *stage = 1;
1432                 *cont = 1;
1433                 if (op->value.boolval) {
1434                     *stage = 5;
1435                     code = setcolorspace_nosubst(i_ctx_p);
1436                     if (code != 0)
1437                         return code;
1438                 }
1439                 break;
1440             case 5:
1441                 /* After stage 4 above, if we had to set a color space, we come
1442                  * here. Now we need to use .includecolorspace to register the space
1443                  * with any high-level devices which want it.
1444                  */
1445                 *stage = 1;
1446                 *cont = 1;
1447                 code = zincludecolorspace(i_ctx_p);
1448                 if (code != 0)
1449                     return code;
1450                 break;
1451         }
1452     } while (*stage);
1453     return code;
1454 }
rgbdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1455 static int rgbdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1456 {
1457     int i;
1458 
1459     for (i = 0;i < 6;i+=2) {
1460         ptr[i] = 0;
1461         ptr[i+1] = 1;
1462     }
1463     return 0;
1464 }
rgbrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1465 static int rgbrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1466 {
1467     int i;
1468 
1469     for (i = 0;i < 6;i+=2) {
1470         ptr[i] = 0;
1471         ptr[i+1] = 1;
1472     }
1473     return 0;
1474 }
1475 /* This routine converts an RGB value into its equivalent in a different
1476  * device space, required by currentgray, currentrgb, currenthsb and
1477  * currentcmyk. The actual color value will have been processed through
1478  * the tint transform(s) of the parent space(s) until it reaches a device
1479  * space. This converts that final value into the requested space.
1480  */
rgbbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1481 static int rgbbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1482 {
1483     os_ptr op = osp;
1484     float RGB[3], CMYK[4], Gray, UCR, BG;
1485     int i;
1486     const gs_color_space *  pcs = gs_currentcolorspace(igs);
1487 
1488     if (pcs->id == cs_DeviceGray_id) {
1489         /* UGLY hack. Its possible for the graphics library to change the
1490          * colour space to DeviceGray (setcachedevice), but this does not
1491          * change the PostScript space. It can't, because the graphics library
1492          * doesn't know about the PostScript objects. If we get a current*
1493          * operation before the space has been restored, the colour space in
1494          * the graphics library and the PostScript stored space won't match.
1495          * If that happens then we need to pretend the PS colour space was
1496          * DeviceGray
1497          */
1498         return(graybasecolor(i_ctx_p, space, base, stage, cont, stack_depth));
1499     }
1500 
1501     switch (*stage) {
1502         case 0:
1503             *cont = 0;
1504             check_op(3);
1505             op -= 2;
1506             for (i=0;i<3;i++) {
1507                 if (!r_has_type(op, t_integer)) {
1508                     if (r_has_type(op, t_real)) {
1509                         RGB[i] = op->value.realval;
1510                     } else
1511                         return_error(e_typecheck);
1512                 } else
1513                     RGB[i] = (float)op->value.intval;
1514                 if (RGB[i] < 0 || RGB[i] > 1)
1515                     return_error(e_rangecheck);
1516                 op++;
1517             }
1518             op = osp;
1519 
1520             switch (base) {
1521                 case 0:
1522                     pop(2);
1523                     op = osp;
1524                     /* If R == G == B, then this is gray, so just use it. Avoids
1525                      * rounding errors.
1526                      */
1527                     if (RGB[0] == RGB[1] && RGB[1] == RGB[2])
1528                         Gray = RGB[0];
1529                     else
1530                         Gray = (0.3 * RGB[0]) + (0.59 * RGB[1]) + (0.11 * RGB[2]);
1531                     make_real(op, Gray);
1532                     return 0;
1533                     break;
1534                 case 1:
1535                     rgb2hsb((float *)&RGB);
1536                     make_real(&op[-2], RGB[0]);
1537                     make_real(&op[-1], RGB[1]);
1538                     make_real(op, RGB[2]);
1539                     return 0;
1540                     break;
1541                 case 2:
1542                     make_real(&op[-2], RGB[0]);
1543                     make_real(&op[-1], RGB[1]);
1544                     make_real(op, RGB[2]);
1545                     return 0;
1546                     break;
1547                 case 3:
1548                     *stage = 1;
1549                     *cont = 1;
1550                     for (i=0;i<3;i++)
1551                         CMYK[i] = 1 - RGB[i];
1552                     if (CMYK[0] < CMYK[1]) {
1553                         if (CMYK[0] < CMYK[2])
1554                             CMYK[3] = CMYK[0];
1555                         else
1556                             CMYK[3] = CMYK[2];
1557                     } else {
1558                         if (CMYK[1] < CMYK[2])
1559                             CMYK[3] = CMYK[1];
1560                         else
1561                             CMYK[3] = CMYK[2];
1562                     }
1563                     check_estack(1);
1564                     push(2);
1565                     op = osp - 4;
1566                     for (i=0;i<4;i++) {
1567                         make_real(op, CMYK[i]);
1568                         op++;
1569                     }
1570                     make_real(op, CMYK[3]);
1571                     esp++;
1572                     *esp = istate->undercolor_removal;
1573                     return o_push_estack;
1574                     break;
1575                 default:
1576                     return_error(e_undefined);
1577                     break;
1578             }
1579             break;
1580         case 1:
1581             (*stage)++;
1582             *cont = 1;
1583             check_estack(1);
1584             check_op(5);
1585             op -= 4;
1586             for (i=0;i<4;i++) {
1587                 if (!r_has_type(op, t_integer)) {
1588                     if (r_has_type(op, t_real)) {
1589                         CMYK[i] = op->value.realval;
1590                     } else
1591                         return_error(e_typecheck);
1592                 } else
1593                     CMYK[i] = (float)op->value.intval;
1594                 op++;
1595             }
1596             if (!r_has_type(op, t_integer)) {
1597                 if (r_has_type(op, t_real)) {
1598                     UCR = op->value.realval;
1599                 } else
1600                     return_error(e_typecheck);
1601             } else
1602                 UCR = (float)op->value.intval;
1603             for (i=0;i<3;i++) {
1604                 CMYK[i] = CMYK[i] - UCR;
1605                 if (CMYK[i] < 0)
1606                     CMYK[i] = 0;
1607                 if (CMYK[i] > 1)
1608                     CMYK[i] = 1.0;
1609             }
1610             op -= 4;
1611             for (i=0;i<4;i++) {
1612                 make_real(op, CMYK[i]);
1613                 op++;
1614             }
1615             make_real(op, CMYK[3]);
1616             esp++;
1617             *esp = istate->black_generation;
1618             return o_push_estack;
1619             break;
1620         case 2:
1621             *stage = 0;
1622             *cont = 0;
1623             check_op(5);
1624             if (!r_has_type(op, t_integer)) {
1625                 if (r_has_type(op, t_real)) {
1626                     BG = op->value.realval;
1627                 } else
1628                     return_error(e_typecheck);
1629             } else
1630                 BG = (float)op->value.intval;
1631             pop(1);
1632             op = osp;
1633             if (BG < 0)
1634                 BG = 0;
1635             if (BG > 1)
1636                 BG = 1;
1637             make_real(op, BG);
1638             break;
1639     }
1640     return 0;
1641 }
rgbvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1642 static int rgbvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1643 {
1644     os_ptr op = osp;
1645     int i;
1646 
1647     if (num_comps < 3)
1648         return_error(e_stackunderflow);
1649 
1650     op -= 2;
1651     for (i=0;i<3;i++) {
1652         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1653             return_error(e_typecheck);
1654         op++;
1655     }
1656 
1657     for (i=0;i < 3; i++) {
1658         if (values[i] > 1.0)
1659             values[i] = 1.0;
1660 
1661         if (values[i] < 0.0)
1662             values[i] = 0.0;
1663     }
1664 
1665     return 0;
1666 }
rgbinitialproc(i_ctx_t * i_ctx_p,ref * space)1667 static int rgbinitialproc(i_ctx_t *i_ctx_p, ref *space)
1668 {
1669     gs_client_color cc;
1670 
1671     cc.pattern = 0x00;
1672     cc.paint.values[0] = 0;
1673     cc.paint.values[1] = 0;
1674     cc.paint.values[2] = 0;
1675     return gs_setcolor(igs, &cc);
1676 }
1677 
1678 /* DeviceCMYK */
setcmykspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)1679 static int setcmykspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
1680 {
1681     os_ptr op = osp;
1682     gs_color_space  *pcs;
1683     int code=0;
1684     ref stref;
1685 
1686     do {
1687         switch (*stage) {
1688             case 0:
1689                 if (istate->use_cie_color.value.boolval && !CIESubst) {
1690                     byte *body;
1691                     ref *nosubst;
1692 
1693                     code = dict_find_string(systemdict, "NOSUBSTDEVICECOLORS", &nosubst);
1694                     if (code < 0)
1695                         return code;
1696                     if (!r_has_type(nosubst, t_boolean))
1697                         return_error(e_typecheck);
1698                     if (nosubst->value.boolval) {
1699                         *stage = 4;
1700                         *cont = 1;
1701                         body = ialloc_string(32, "string");
1702                         if (body == 0)
1703                             return_error(e_VMerror);
1704                         memcpy(body, "/DefaultCMYK ..nosubstdevicetest",32);
1705                         make_string(&stref, a_all | icurrent_space, 32, body);
1706                         r_set_attrs(&stref, a_executable);
1707                         esp++;
1708                         ref_assign(esp, &stref);
1709                         return o_push_estack;
1710                     } else {
1711                         *stage = 2;
1712                         *cont = 1;
1713                         body = ialloc_string(47, "string");
1714                         if (body == 0)
1715                             return_error(e_VMerror);
1716                         memcpy(body, "{/DefaultCMYK /ColorSpace findresource} stopped", 47);
1717                         make_string(&stref, a_all | icurrent_space, 47, body);
1718                         r_set_attrs(&stref, a_executable);
1719                         esp++;
1720                         ref_assign(esp, &stref);
1721                         return o_push_estack;
1722                     }
1723                 }
1724                 /* fall through */
1725             case 1:
1726                 pcs = gs_cspace_new_DeviceCMYK(imemory);
1727                 if (pcs == NULL)
1728                     return_error(e_VMerror);
1729                 code = gs_setcolorspace(igs, pcs);
1730                 if (code >= 0) {
1731                     gs_client_color *pcc = gs_currentcolor_inline(igs);
1732 
1733                     cs_adjust_color_count(igs, -1); /* not strictly necessary */
1734                     pcc->paint.values[0] = 0;
1735                     pcc->paint.values[1] = 0;
1736                     pcc->paint.values[2] = 0;
1737                     pcc->paint.values[3] = 1;
1738                     pcc->pattern = 0;		/* for GC */
1739                     gx_unset_dev_color(igs);
1740                 }
1741                 rc_decrement_only_cs(pcs, "zsetdevcspace");
1742                 *cont = 0;
1743                 *stage = 0;
1744                 break;
1745             case 2:
1746                 if (!r_has_type(op, t_boolean))
1747                     return_error(e_typecheck);
1748                 if (op->value.boolval) {
1749                     /* Failed to find the /DefaultCMYK CSA, so give up and
1750                      * just use DeviceCMYK
1751                      */
1752                     pop(1);
1753                     *stage = 1;
1754                     break;
1755                 }
1756                 pop(1);
1757                 *stage = 3;
1758                 code = setcolorspace_nosubst(i_ctx_p);
1759                 if (code != 0)
1760                     return code;
1761                 break;
1762             case 3:
1763                 /* We end up here after setting the DefaultGray CIE space
1764                  * We've finished setting the gray color space, so we
1765                  * just exit now
1766                  */
1767                 *cont = 0;
1768                 *stage = 0;
1769                 break;
1770             case 4:
1771                 /* We come here if /UseCIEColor is true, and NOSUBSTDEVICECOLORS
1772                  * is also true. We will have a boolean on the stack, if its true
1773                  * then we need to set the space (also on the stack), invoke
1774                  * .includecolorspace, and set /DeviceGray, otherwise we just need
1775                  * to set DeviceGray. See gs-cspace.ps.
1776                  */
1777                 if (!r_has_type(op, t_boolean))
1778                     return_error(e_typecheck);
1779                 pop(1);
1780                 *stage = 1;
1781                 *cont = 1;
1782                 if (op->value.boolval) {
1783                     *stage = 5;
1784                     code = setcolorspace_nosubst(i_ctx_p);
1785                     if (code != 0)
1786                         return code;
1787                 }
1788                 break;
1789             case 5:
1790                 /* After stage 4 above, if we had to set a color space, we come
1791                  * here. Now we need to use .includecolorspace to register the space
1792                  * with any high-level devices which want it.
1793                  */
1794                 *stage = 1;
1795                 *cont = 1;
1796                 code = zincludecolorspace(i_ctx_p);
1797                 if (code != 0)
1798                     return code;
1799                 break;
1800         }
1801     } while (*stage);
1802     return code;
1803 }
cmykdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)1804 static int cmykdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1805 {
1806     int i;
1807 
1808     for (i = 0;i < 8;i+=2) {
1809         ptr[i] = 0;
1810         ptr[i+1] = 1;
1811     }
1812     return 0;
1813 }
cmykrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)1814 static int cmykrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
1815 {
1816     int i;
1817 
1818     for (i = 0;i < 8;i+=2) {
1819         ptr[i] = 0;
1820         ptr[i+1] = 1;
1821     }
1822     return 0;
1823 }
1824 /* This routine converts a CMYK value into its equivalent in a different
1825  * device space, required by currentgray, currentrgb, currenthsb and
1826  * currentcmyk. The actual color value will have been processed through
1827  * the tint transform(s) of the parent space(s) until it reaches a device
1828  * space. This converts that final value into the requested space.
1829  */
cmykbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)1830 static int cmykbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
1831 {
1832     os_ptr op = osp;
1833     float CMYK[4], Gray, RGB[3];
1834     int i;
1835     const gs_color_space *  pcs = gs_currentcolorspace(igs);
1836 
1837     if (pcs->id == cs_DeviceGray_id) {
1838         /* UGLY hack. Its possible for the graphics library to change the
1839          * colour space to DeviceGray (setcachedevice), but this does not
1840          * change the PostScript space. It can't, because the graphics library
1841          * doesn't know about the PostScript objects. If we get a current*
1842          * operation before the space has been restored, the colour space in
1843          * the graphics library and the PostScript stored space won't match.
1844          * If that happens then we need to pretend the PS colour space was
1845          * DeviceGray
1846          */
1847         return(graybasecolor(i_ctx_p, space, base, stage, cont, stack_depth));
1848     }
1849 
1850     *cont = 0;
1851     *stage = 0;
1852     check_op(4);
1853     op -= 3;
1854     for (i=0;i<4;i++) {
1855         if (!r_has_type(op, t_integer)) {
1856             if (r_has_type(op, t_real)) {
1857                 CMYK[i] = op->value.realval;
1858             } else
1859                 return_error(e_typecheck);
1860         } else
1861             CMYK[i] = (float)op->value.intval;
1862         if (CMYK[i] < 0 || CMYK[i] > 1)
1863             return_error(e_rangecheck);
1864         op++;
1865     }
1866 
1867     switch (base) {
1868         case 0:
1869             pop(3);
1870             op = osp;
1871             Gray = (0.3 * CMYK[0]) + (0.59 * CMYK[1]) + (0.11 * CMYK[2]) + CMYK[3];
1872             if (Gray > 1.0)
1873                 Gray = 0;
1874             else
1875                 Gray = 1.0 - Gray;
1876             make_real(op, Gray);
1877             break;
1878         case 1:
1879         case 2:
1880             pop(1);
1881             op = osp;
1882             RGB[0] = 1.0 - (CMYK[0] + CMYK[3]);
1883             if (RGB[0] < 0)
1884                 RGB[0] = 0;
1885             RGB[1] = 1.0 - (CMYK[1] + CMYK[3]);
1886             if (RGB[1] < 0)
1887                 RGB[1] = 0;
1888             RGB[2] = 1.0 - (CMYK[2] + CMYK[3]);
1889             if (RGB[2] < 0)
1890                 RGB[2] = 0;
1891             if (base == 1)
1892                 rgb2hsb((float *)&RGB);
1893             make_real(&op[-2], RGB[0]);
1894             make_real(&op[-1], RGB[1]);
1895             make_real(op, RGB[2]);
1896             break;
1897         case 3:
1898             op = osp;
1899             make_real(&op[-3], CMYK[0]);
1900             make_real(&op[-2], CMYK[1]);
1901             make_real(&op[-1], CMYK[2]);
1902             make_real(op, CMYK[3]);
1903             break;
1904         default:
1905             return_error(e_undefined);
1906     }
1907     return 0;
1908 }
cmykvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)1909 static int cmykvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
1910 {
1911     os_ptr op = osp;
1912     int i;
1913 
1914     if (num_comps < 4)
1915         return_error(e_stackunderflow);
1916 
1917     op -= 3;
1918     for (i=0;i < 4;i++) {
1919         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
1920             return_error(e_typecheck);
1921         op++;
1922     }
1923 
1924     for (i=0;i < 4; i++) {
1925         if (values[i] > 1.0)
1926             values[i] = 1.0;
1927 
1928         if (values[i] < 0.0)
1929             values[i] = 0.0;
1930     }
1931 
1932     return 0;
1933 }
cmykinitialproc(i_ctx_t * i_ctx_p,ref * space)1934 static int cmykinitialproc(i_ctx_t *i_ctx_p, ref *space)
1935 {
1936     gs_client_color cc;
1937 
1938     cc.pattern = 0x00;
1939     cc.paint.values[0] = 0;
1940     cc.paint.values[1] = 0;
1941     cc.paint.values[2] = 0;
1942     cc.paint.values[3] = 1;
1943     return gs_setcolor(igs, &cc);
1944 }
1945 
1946 /* CIEBased */
1947 /* A utility routine to check whether two arrays contain the same
1948  * contents. Used to check whether two color spaces are the same
1949  * Note that this can be recursive if the array contains arrays.
1950  */
comparearrays(i_ctx_t * i_ctx_p,ref * m1,ref * m2)1951 static int comparearrays(i_ctx_t * i_ctx_p, ref *m1, ref *m2)
1952 {
1953     int i, code;
1954     ref ref1, ref2;
1955 
1956     if (r_size(m1) != r_size(m2))
1957         return 0;
1958 
1959     for (i=0;i < r_size(m1);i++) {
1960         code = array_get(imemory, m1, i, &ref1);
1961         if (code < 0)
1962             return 0;
1963         code = array_get(imemory, m2, i, &ref2);
1964         if (code < 0)
1965             return 0;
1966 
1967         if (r_type(&ref1) != r_type(&ref2))
1968             return 0;
1969 
1970         code = r_type(&ref1);
1971         switch(r_type(&ref1)) {
1972             case t_null:
1973                 break;
1974             case t_boolean:
1975                 if (ref1.value.boolval != ref2.value.boolval)
1976                     return 0;
1977                 break;
1978             case t_integer:
1979                 if (ref1.value.intval != ref2.value.intval)
1980                     return 0;
1981                 break;
1982             case t_real:
1983                 if (ref1.value.realval != ref2.value.realval)
1984                     return 0;
1985                 break;
1986             case t_name:
1987                 if (!name_eq(&ref1, &ref2))
1988                     return 0;
1989                 break;
1990             case t_string:
1991                 if (r_size(&ref1) != r_size(&ref2))
1992                     return 0;
1993                 if (strncmp((const char *)ref1.value.const_bytes, (const char *)ref2.value.const_bytes, r_size(&ref1)) != 0)
1994                     return 0;
1995                 break;
1996             case t_array:
1997             case t_mixedarray:
1998             case t_shortarray:
1999                 if (!comparearrays(i_ctx_p, &ref1, &ref2))
2000                     return 0;
2001                 break;
2002             case t_oparray:
2003                 break;
2004             case t_operator:
2005                 if (ref1.value.opproc != ref2.value.opproc)
2006                     return 0;
2007                 break;
2008             case t__invalid:
2009             case t_dictionary:
2010             case t_file:
2011             case t_unused_array_:
2012             case t_struct:
2013             case t_astruct:
2014             case t_fontID:
2015             case t_save:
2016             case t_mark:
2017             case t_device:
2018                 return 0;
2019             default:
2020                 /* Some high frequency operators are defined starting at t_next_index
2021                  * I think as long as the 'type' of each is the same, we are OK
2022                  */
2023                 break;
2024         }
2025     }
2026     return 1;
2027 }
2028 /* A utility routine to check whether two dictionaries contain the same
2029  * arrays. This is a simple routine, unlike comparearrays above it is only
2030  * used by the CIE comparison code and expects only to check that the
2031  * dictionary contains an array, and checks the arrays.
2032  */
comparedictkey(i_ctx_t * i_ctx_p,ref * CIEdict1,ref * CIEdict2,char * key)2033 static int comparedictkey(i_ctx_t * i_ctx_p, ref *CIEdict1, ref *CIEdict2, char *key)
2034 {
2035     int code, code1;
2036     ref *tempref1, *tempref2;
2037 
2038     code = dict_find_string(CIEdict1, key, &tempref1);
2039     code1 = dict_find_string(CIEdict2, key, &tempref2);
2040     if (code != code1)
2041         return 0;
2042 
2043     if (code < 0)
2044         return 1;
2045 
2046     if (r_type(tempref1) != r_type(tempref2))
2047         return 0;
2048 
2049     if (r_type(tempref1) == t_null)
2050         return 1;
2051 
2052     return comparearrays(i_ctx_p, tempref1, tempref2);
2053 }
2054 
2055 /* Check that the WhitePoint of a CIE space is valid */
checkWhitePoint(i_ctx_t * i_ctx_p,ref * CIEdict)2056 static int checkWhitePoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2057 {
2058     int code = 0, i;
2059     float value[3];
2060     ref *tempref, valref;
2061 
2062     code = dict_find_string(CIEdict, "WhitePoint", &tempref);
2063     if (code < 0 || r_has_type(tempref, t_null))
2064         return code;
2065 
2066     if (!r_is_array(tempref))
2067         return_error(e_typecheck);
2068     if (r_size(tempref) != 3)
2069         return_error(e_rangecheck);
2070 
2071     for (i=0;i<3;i++) {
2072         code = array_get(imemory, tempref, i, &valref);
2073         if (code < 0)
2074             return code;
2075         if (r_has_type(&valref, t_integer))
2076             value[i] = (float)valref.value.intval;
2077         else if (r_has_type(&valref, t_real))
2078             value[i] = (float)valref.value.realval;
2079         else
2080             return_error(e_typecheck);
2081     }
2082     /* Xw and Zw must be positive and Yw must be 1 (3rd edition PLRM p230) */
2083     if (value[0] < 0 || value[1] != 1 || value[2] < 0 )
2084             return_error(e_rangecheck);
2085 
2086     return 0;
2087 }
2088 /* Check that the BlackPoint of a CIE space is valid */
checkBlackPoint(i_ctx_t * i_ctx_p,ref * CIEdict)2089 static int checkBlackPoint(i_ctx_t * i_ctx_p, ref *CIEdict)
2090 {
2091     int code = 0, i;
2092     float value[3];
2093     ref *tempref, valref;
2094 
2095     code = dict_find_string(CIEdict, "BlackPoint", &tempref);
2096     if (code >= 0 && !r_has_type(tempref, t_null)) {
2097         if (!r_is_array(tempref))
2098             return_error(e_typecheck);
2099         if (r_size(tempref) != 3)
2100             return_error(e_rangecheck);
2101 
2102         for (i=0;i<3;i++) {
2103             code = array_get(imemory, tempref, i, &valref);
2104             if (code < 0)
2105                 return code;
2106             if (r_has_type(&valref, t_integer))
2107                 value[i] = (float)valref.value.intval;
2108             else if (r_has_type(&valref, t_real))
2109                 value[i] = (float)valref.value.realval;
2110             else
2111                 return_error(e_typecheck);
2112         }
2113     }
2114     return 0;
2115 }
2116 /* Check that the RangeLMN of a CIE space is valid */
checkRangeLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2117 static int checkRangeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2118 {
2119     int code = 0, i;
2120     float value[6];
2121     ref *tempref, valref;
2122 
2123     code = dict_find_string(CIEdict, "RangeLMN", &tempref);
2124     if (code >= 0 && !r_has_type(tempref, t_null)) {
2125         if (!r_is_array(tempref))
2126             return_error(e_typecheck);
2127         if (r_size(tempref) != 6)
2128             return_error(e_rangecheck);
2129 
2130         for (i=0;i<6;i++) {
2131             code = array_get(imemory, tempref, i, &valref);
2132             if (code < 0)
2133                 return code;
2134             if (r_has_type(&valref, t_integer))
2135                 value[i] = (float)valref.value.intval;
2136             else if (r_has_type(&valref, t_real))
2137                 value[i] = (float)valref.value.realval;
2138             else
2139                 return_error(e_typecheck);
2140         }
2141         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2142             return_error(e_rangecheck);
2143     }
2144     return 0;
2145 }
2146 /* Check that the DecodeLMN of a CIE space is valid */
checkDecodeLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2147 static int checkDecodeLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2148 {
2149     int code = 0, i;
2150     ref *tempref, valref;
2151 
2152     code = dict_find_string(CIEdict, "DecodeLMN", &tempref);
2153     if (code >= 0 && !r_has_type(tempref, t_null)) {
2154         if (!r_is_array(tempref))
2155             return_error(e_typecheck);
2156         if (r_size(tempref) != 3)
2157             return_error(e_rangecheck);
2158 
2159         for (i=0;i<3;i++) {
2160             code = array_get(imemory, tempref, i, &valref);
2161             if (code < 0)
2162                 return code;
2163             check_proc(valref);
2164         }
2165     }
2166     return 0;
2167 }
2168 /* Check that the MatrixLMN of a CIE space is valid */
checkMatrixLMN(i_ctx_t * i_ctx_p,ref * CIEdict)2169 static int checkMatrixLMN(i_ctx_t * i_ctx_p, ref *CIEdict)
2170 {
2171     int code = 0, i;
2172     float value[9];
2173     ref *tempref, valref;
2174 
2175     code = dict_find_string(CIEdict, "MatrixLMN", &tempref);
2176     if (code >= 0 && !r_has_type(tempref, t_null)) {
2177         if (!r_is_array(tempref))
2178             return_error(e_typecheck);
2179         if (r_size(tempref) != 9)
2180             return_error(e_rangecheck);
2181 
2182         for (i=0;i<9;i++) {
2183             code = array_get(imemory, tempref, i, &valref);
2184             if (code < 0)
2185                 return code;
2186             if (r_has_type(&valref, t_integer))
2187                 value[i] = (float)valref.value.intval;
2188             else if (r_has_type(&valref, t_real))
2189                 value[i] = (float)valref.value.realval;
2190             else
2191                 return_error(e_typecheck);
2192         }
2193     }
2194     return 0;
2195 }
2196 
2197 /* CIEBasedA */
setcieaspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2198 static int setcieaspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2199 {
2200     int code = 0;
2201     ref CIEDict, *nocie;
2202     ulong dictkey;
2203 
2204     if (i_ctx_p->language_level < 2)
2205         return_error(e_undefined);
2206 
2207     code = dict_find_string(systemdict, "NOCIE", &nocie);
2208     if (code < 0)
2209         return code;
2210     if (!r_has_type(nocie, t_boolean))
2211         return_error(e_typecheck);
2212     if (nocie->value.boolval)
2213         return setgrayspace(i_ctx_p, r, stage, cont, 1);
2214 
2215     *cont = 0;
2216     code = array_get(imemory, r, 1, &CIEDict);
2217     if (code < 0)
2218         return code;
2219     if ((*stage) > 0) {
2220         gs_client_color cc;
2221 
2222         cc.pattern = 0x00;
2223         cc.paint.values[0] = 0;
2224         code = gs_setcolor(igs, &cc);
2225         *stage = 0;
2226         return code;
2227     }
2228     dictkey = r->value.refs->value.saveid;
2229     code = cieaspace(i_ctx_p, &CIEDict, dictkey);
2230     (*stage)++;
2231     *cont = 1;
2232     return code;
2233 }
validatecieaspace(i_ctx_t * i_ctx_p,ref ** r)2234 static int validatecieaspace(i_ctx_t * i_ctx_p, ref **r)
2235 {
2236     int code = 0, i;
2237     float value[9];
2238     ref     CIEdict, *CIEspace = *r, *tempref, valref;
2239 
2240     if (!r_is_array(CIEspace))
2241         return_error(e_typecheck);
2242     /* Validate parameters, check we have enough operands */
2243     if (r_size(CIEspace) != 2)
2244         return_error(e_rangecheck);
2245 
2246     code = array_get(imemory, CIEspace, 1, &CIEdict);
2247     if (code < 0)
2248         return code;
2249 
2250     check_read_type(CIEdict, t_dictionary);
2251 
2252     /* Check white point exists, and is an array of three numbers */
2253     code = checkWhitePoint(i_ctx_p, &CIEdict);
2254     if (code != 0)
2255         return code;
2256 
2257     /* Remaining parameters are optional, but we must validate
2258      * them if they are present
2259      */
2260     code = dict_find_string(&CIEdict, "RangeA", &tempref);
2261     if (code >= 0 && !r_has_type(tempref, t_null)) {
2262         /* Array of two numbers A0 < A1 */
2263         if (!r_is_array(tempref))
2264             return_error(e_typecheck);
2265         if (r_size(tempref) != 2)
2266             return_error(e_rangecheck);
2267 
2268         for (i=0;i<2;i++) {
2269             code = array_get(imemory, tempref, i, &valref);
2270             if (code < 0)
2271                 return code;
2272             if (r_has_type(&valref, t_integer))
2273                 value[i] = (float)valref.value.intval;
2274             else if (r_has_type(&valref, t_real))
2275                 value[i] = (float)valref.value.realval;
2276             else
2277                 return_error(e_typecheck);
2278         }
2279         if (value[1] < value[0])
2280             return_error(e_rangecheck);
2281     }
2282 
2283     code = dict_find_string(&CIEdict, "DecodeA", &tempref);
2284     if (code >= 0 && !r_has_type(tempref, t_null)) {
2285         check_proc(*tempref);
2286     }
2287 
2288     code = dict_find_string(&CIEdict, "MatrixA", &tempref);
2289     if (code >= 0 && !r_has_type(tempref, t_null)) {
2290         if (!r_is_array(tempref))
2291             return_error(e_typecheck);
2292         if (r_size(tempref) != 3)
2293             return_error(e_rangecheck);
2294 
2295         for (i=0;i<3;i++) {
2296             code = array_get(imemory, tempref, i, &valref);
2297             if (code < 0)
2298                 return code;
2299             if (r_has_type(&valref, t_integer))
2300                 value[i] = (float)valref.value.intval;
2301             else if (r_has_type(&valref, t_real))
2302                 value[i] = (float)valref.value.realval;
2303             else
2304                 return_error(e_typecheck);
2305         }
2306     }
2307 
2308     code = checkRangeLMN(i_ctx_p, &CIEdict);
2309     if (code != 0)
2310         return code;
2311 
2312     code = checkDecodeLMN(i_ctx_p, &CIEdict);
2313     if (code != 0)
2314         return code;
2315 
2316     code = checkMatrixLMN(i_ctx_p, &CIEdict);
2317     if (code != 0)
2318         return code;
2319 
2320     code = checkBlackPoint(i_ctx_p, &CIEdict);
2321     if (code != 0)
2322         return code;
2323 
2324     *r = 0;
2325     return 0;
2326 }
cieadomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2327 static int cieadomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2328 {
2329     int i, code;
2330     ref     CIEdict, *tempref, valref;
2331 
2332     code = array_get(imemory, space, 1, &CIEdict);
2333     if (code < 0)
2334         return code;
2335 
2336     /* If we have a RangeA entry in the dictionary, get the
2337      * values from that
2338      */
2339     code = dict_find_string(&CIEdict, "RangeA", &tempref);
2340     if (code >= 0 && !r_has_type(tempref, t_null)) {
2341         for (i=0;i<2;i++) {
2342             code = array_get(imemory, tempref, i, &valref);
2343             if (code < 0)
2344                 return code;
2345             if (r_has_type(&valref, t_integer))
2346                 ptr[i] = (float)valref.value.intval;
2347             else if (r_has_type(&valref, t_real))
2348                 ptr[i] = (float)valref.value.realval;
2349             else
2350                 return_error(e_typecheck);
2351         }
2352     } else {
2353         /* Default values for CIEBasedA */
2354         ptr[0] = 0;
2355         ptr[1] = 1;
2356     }
2357     return 0;
2358 }
ciearange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2359 static int ciearange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2360 {
2361     int i, code;
2362     ref     CIEdict, *tempref, valref;
2363 
2364     code = array_get(imemory, space, 1, &CIEdict);
2365     if (code < 0)
2366         return code;
2367 
2368     /* If we have a RangeA entry in the dictionary, get the
2369      * values from that
2370      */
2371     code = dict_find_string(&CIEdict, "RangeA", &tempref);
2372     if (code >= 0 && !r_has_type(tempref, t_null)) {
2373         for (i=0;i<2;i++) {
2374             code = array_get(imemory, tempref, i, &valref);
2375             if (code < 0)
2376                 return code;
2377             if (r_has_type(&valref, t_integer))
2378                 ptr[i] = (float)valref.value.intval;
2379             else if (r_has_type(&valref, t_real))
2380                 ptr[i] = (float)valref.value.realval;
2381             else
2382                 return_error(e_typecheck);
2383         }
2384     } else {
2385         /* Default values for CIEBasedA */
2386         ptr[0] = 0;
2387         ptr[1] = 1;
2388     }
2389     return 0;
2390 }
cieavalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2391 static int cieavalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2392 {
2393     os_ptr op = osp;
2394 
2395     if (num_comps < 1)
2396         return_error(e_stackunderflow);
2397 
2398     if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2399         return_error(e_typecheck);
2400 
2401     return 0;
2402 }
cieacompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2403 static int cieacompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2404 {
2405     int code = 0;
2406     ref CIEdict1, CIEdict2;
2407 
2408     code = array_get(imemory, space, 1, &CIEdict1);
2409     if (code < 0)
2410         return 0;
2411     code = array_get(imemory, testspace, 1, &CIEdict2);
2412     if (code < 0)
2413         return 0;
2414     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2415         return 0;
2416     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2417         return 0;
2418     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeA"))
2419         return 0;
2420     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeA"))
2421         return 0;
2422     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixA"))
2423         return 0;
2424     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2425         return 0;
2426     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2427         return 0;
2428     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2429         return 0;
2430     return 1;
2431 }
2432 
2433 /* CIEBasedABC */
setcieabcspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2434 static int setcieabcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2435 {
2436     int code = 0;
2437     ref CIEDict, *nocie;
2438     ulong dictkey;
2439 
2440     if (i_ctx_p->language_level < 2)
2441         return_error(e_undefined);
2442 
2443     code = dict_find_string(systemdict, "NOCIE", &nocie);
2444     if (code < 0)
2445         return code;
2446     if (!r_has_type(nocie, t_boolean))
2447         return_error(e_typecheck);
2448     if (nocie->value.boolval)
2449         return setrgbspace(i_ctx_p, r, stage, cont, 1);
2450 
2451     *cont = 0;
2452     code = array_get(imemory, r, 1, &CIEDict);
2453     if (code < 0)
2454         return code;
2455 
2456     if ((*stage) > 0) {
2457         gs_client_color cc;
2458         int i;
2459 
2460         cc.pattern = 0x00;
2461         for (i=0;i<3;i++)
2462             cc.paint.values[i] = 0;
2463         code = gs_setcolor(igs, &cc);
2464         *stage = 0;
2465         return code;
2466     }
2467     dictkey = r->value.refs->value.saveid;
2468     code = cieabcspace(i_ctx_p, &CIEDict,dictkey);
2469     *cont = 1;
2470     (*stage)++;
2471     return code;
2472 }
validatecieabcspace(i_ctx_t * i_ctx_p,ref ** r)2473 static int validatecieabcspace(i_ctx_t * i_ctx_p, ref **r)
2474 {
2475     int code = 0, i;
2476     float value[9];
2477     ref     CIEdict, *CIEspace = *r, *tempref, valref;
2478 
2479     if (!r_is_array(CIEspace))
2480         return_error(e_typecheck);
2481     /* Validate parameters, check we have enough operands */
2482     if (r_size(CIEspace) != 2)
2483         return_error(e_rangecheck);
2484 
2485     code = array_get(imemory, CIEspace, 1, &CIEdict);
2486     if (code < 0)
2487         return code;
2488     check_read_type(CIEdict, t_dictionary);
2489 
2490     /* Check white point exists, and is an array of three numbers */
2491     code = checkWhitePoint(i_ctx_p, &CIEdict);
2492     if (code != 0)
2493         return code;
2494 
2495     /* Remaining parameters are optional, but we must validate
2496      * them if they are present
2497      */
2498     code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2499     if (code >= 0 && !r_has_type(tempref, t_null)) {
2500         if (!r_is_array(tempref))
2501             return_error(e_typecheck);
2502         if (r_size(tempref) != 6)
2503             return_error(e_rangecheck);
2504 
2505         for (i=0;i<6;i++) {
2506             code = array_get(imemory, tempref, i, &valref);
2507             if (code < 0)
2508                 return code;
2509             if (r_has_type(&valref, t_integer))
2510                 value[i] = (float)valref.value.intval;
2511             else if (r_has_type(&valref, t_real))
2512                 value[i] = (float)valref.value.realval;
2513             else
2514                 return_error(e_typecheck);
2515         }
2516         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2517             return_error(e_rangecheck);
2518     }
2519 
2520     code = dict_find_string(&CIEdict, "DecodeABC", &tempref);
2521     if (code >= 0 && !r_has_type(tempref, t_null)) {
2522         if (!r_is_array(tempref))
2523             return_error(e_typecheck);
2524         if (r_size(tempref) != 3)
2525             return_error(e_rangecheck);
2526 
2527         for (i=0;i<3;i++) {
2528             code = array_get(imemory, tempref, i, &valref);
2529             if (code < 0)
2530                 return code;
2531             check_proc(valref);
2532         }
2533     }
2534 
2535     code = dict_find_string(&CIEdict, "MatrixABC", &tempref);
2536     if (code >= 0 && !r_has_type(tempref, t_null)) {
2537         if (!r_is_array(tempref))
2538             return_error(e_typecheck);
2539         if (r_size(tempref) != 9)
2540             return_error(e_rangecheck);
2541 
2542         for (i=0;i<9;i++) {
2543             code = array_get(imemory, tempref, i, &valref);
2544             if (code < 0)
2545                 return code;
2546             if (r_has_type(&valref, t_integer))
2547                 value[i] = (float)valref.value.intval;
2548             else if (r_has_type(&valref, t_real))
2549                 value[i] = (float)valref.value.realval;
2550             else
2551                 return_error(e_typecheck);
2552         }
2553     }
2554 
2555     code = checkRangeLMN(i_ctx_p, &CIEdict);
2556     if (code != 0)
2557         return code;
2558 
2559     code = checkDecodeLMN(i_ctx_p, &CIEdict);
2560     if (code != 0)
2561         return code;
2562 
2563     code = checkMatrixLMN(i_ctx_p, &CIEdict);
2564     if (code != 0)
2565         return code;
2566 
2567     code = checkBlackPoint(i_ctx_p, &CIEdict);
2568     if (code != 0)
2569         return code;
2570 
2571     *r = 0;
2572     return 0;
2573 }
cieabcdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2574 static int cieabcdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2575 {
2576     int i, code;
2577     ref     CIEdict, *tempref, valref;
2578 
2579     code = array_get(imemory, space, 1, &CIEdict);
2580     if (code < 0)
2581         return code;
2582 
2583     /* If we have a RangeABC, get the values from that */
2584     code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2585     if (code >= 0 && !r_has_type(tempref, t_null)) {
2586         for (i=0;i<6;i++) {
2587             code = array_get(imemory, tempref, i, &valref);
2588             if (code < 0)
2589                 return code;
2590             if (r_has_type(&valref, t_integer))
2591                 ptr[i] = (float)valref.value.intval;
2592             else if (r_has_type(&valref, t_real))
2593                 ptr[i] = (float)valref.value.realval;
2594             else
2595                 return_error(e_typecheck);
2596         }
2597     } else {
2598         /* Default values for CIEBasedABC */
2599         for (i=0;i<3;i++) {
2600             ptr[2 * i] = 0;
2601             ptr[(2 * i) + 1] = 1;
2602         }
2603     }
2604     return 0;
2605 }
cieabcrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2606 static int cieabcrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2607 {
2608     int i, code;
2609     ref     CIEdict, *tempref, valref;
2610 
2611     code = array_get(imemory, space, 1, &CIEdict);
2612     if (code < 0)
2613         return code;
2614 
2615     /* If we have a RangeABC, get the values from that */
2616     code = dict_find_string(&CIEdict, "RangeABC", &tempref);
2617     if (code >= 0 && !r_has_type(tempref, t_null)) {
2618         for (i=0;i<6;i++) {
2619             code = array_get(imemory, tempref, i, &valref);
2620             if (code < 0)
2621                 return code;
2622             if (r_has_type(&valref, t_integer))
2623                 ptr[i] = (float)valref.value.intval;
2624             else if (r_has_type(&valref, t_real))
2625                 ptr[i] = (float)valref.value.realval;
2626             else
2627                 return_error(e_typecheck);
2628         }
2629     } else {
2630         /* Default values for CIEBasedABC */
2631         for (i=0;i<3;i++) {
2632             ptr[2 * i] = 0;
2633             ptr[(2 * i) + 1] = 1;
2634         }
2635     }
2636     return 0;
2637 }
cieabcvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2638 static int cieabcvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2639 {
2640     os_ptr op = osp;
2641     int i;
2642 
2643     if (num_comps < 3)
2644         return_error(e_stackunderflow);
2645 
2646     op -= 2;
2647     for (i=0;i<3;i++) {
2648         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2649             return_error(e_typecheck);
2650         op++;
2651     }
2652 
2653     return 0;
2654 }
cieabccompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2655 static int cieabccompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2656 {
2657     int code = 0;
2658     ref CIEdict1, CIEdict2;
2659 
2660     code = array_get(imemory, space, 1, &CIEdict1);
2661     if (code < 0)
2662         return 0;
2663     code = array_get(imemory, testspace, 1, &CIEdict2);
2664     if (code < 0)
2665         return 0;
2666     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2667         return 0;
2668     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2669         return 0;
2670     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2671         return 0;
2672     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2673         return 0;
2674     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2675         return 0;
2676     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2677         return 0;
2678     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2679         return 0;
2680     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2681         return 0;
2682     return 1;
2683 }
2684 
2685 /* CIEBasedDEF */
setciedefspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2686 static int setciedefspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2687 {
2688     int code = 0;
2689     ref CIEDict, *nocie;
2690     ulong dictkey;
2691 
2692     if (i_ctx_p->language_level < 3)
2693         return_error(e_undefined);
2694 
2695     code = dict_find_string(systemdict, "NOCIE", &nocie);
2696     if (code < 0)
2697         return code;
2698     if (!r_has_type(nocie, t_boolean))
2699         return_error(e_typecheck);
2700     if (nocie->value.boolval)
2701         return setrgbspace(i_ctx_p, r, stage, cont, 1);
2702 
2703     *cont = 0;
2704     code = array_get(imemory, r, 1, &CIEDict);
2705     if (code < 0)
2706         return code;
2707     if ((*stage) > 0) {
2708         gs_client_color cc;
2709         int i;
2710 
2711         cc.pattern = 0x00;
2712         for (i=0;i<3;i++)
2713             cc.paint.values[i] = 0;
2714         code = gs_setcolor(igs, &cc);
2715         *stage = 0;
2716         return code;
2717     }
2718     dictkey = r->value.refs->value.saveid;
2719     code = ciedefspace(i_ctx_p, &CIEDict, dictkey);
2720     *cont = 1;
2721     (*stage)++;
2722     return code;
2723 }
validateciedefspace(i_ctx_t * i_ctx_p,ref ** r)2724 static int validateciedefspace(i_ctx_t * i_ctx_p, ref **r)
2725 {
2726     int code = 0, i;
2727     float value[6];
2728     ref     CIEdict, *pref, *CIEspace = *r, tempref, valref;
2729 
2730     if (!r_is_array(CIEspace))
2731         return_error(e_typecheck);
2732     /* Validate parameters, check we have enough operands */
2733     if (r_size(CIEspace) != 2)
2734         return_error(e_rangecheck);
2735 
2736     code = array_get(imemory, CIEspace, 1, &CIEdict);
2737     if (code < 0)
2738         return code;
2739     check_read_type(CIEdict, t_dictionary);
2740 
2741     code = validatecieabcspace(i_ctx_p, r);
2742     if (code != 0)
2743         return code;
2744 
2745     pref = &tempref;
2746     code = dict_find_string(&CIEdict, "Table", &pref);
2747     if (code >= 0) {
2748         if (!r_is_array(pref))
2749             return_error(e_typecheck);
2750         if (r_size(pref) != 4)
2751             return_error(e_rangecheck);
2752 
2753         for (i=0;i<3;i++) {
2754             code = array_get(imemory, pref, i, &valref);
2755             if (code < 0)
2756                 return code;
2757             if (r_has_type(&valref, t_integer))
2758                 value[i] = (float)valref.value.intval;
2759             else
2760                 return_error(e_typecheck);
2761         }
2762         if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1)
2763             return_error(e_rangecheck);
2764 
2765         code = array_get(imemory, pref, 3, &valref);
2766         if (code < 0)
2767             return code;
2768         if (!r_is_array(&valref))
2769             return_error(e_typecheck);
2770         if (r_size(&valref) != value[0])
2771             return_error(e_rangecheck);
2772 
2773         for (i=0;i<value[0];i++) {
2774             code = array_get(imemory, &valref, i, &tempref);
2775             if (code < 0)
2776                 return code;
2777             if (!r_has_type(&tempref, t_string))
2778                 return_error(e_typecheck);
2779 
2780             if (r_size(&tempref) != (3 * value[1] * value[2]))
2781                 return_error(e_rangecheck);
2782         }
2783     } else {
2784         return_error(e_rangecheck);
2785     }
2786 
2787     /* Remaining parameters are optional, but we must validate
2788      * them if they are present
2789      */
2790     code = dict_find_string(&CIEdict, "RangeDEF", &pref);
2791     if (code >= 0 && !r_has_type(&tempref, t_null)) {
2792         if (!r_is_array(pref))
2793             return_error(e_typecheck);
2794         if (r_size(pref) != 6)
2795             return_error(e_rangecheck);
2796 
2797         for (i=0;i<6;i++) {
2798             code = array_get(imemory, pref, i, &valref);
2799             if (code < 0)
2800                 return code;
2801             if (r_has_type(&valref, t_integer))
2802                 value[i] = (float)valref.value.intval;
2803             else if (r_has_type(&valref, t_real))
2804                 value[i] = (float)valref.value.realval;
2805             else
2806                 return_error(e_typecheck);
2807         }
2808         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2809             return_error(e_rangecheck);
2810     }
2811 
2812     code = dict_find_string(&CIEdict, "DecodeDEF", &pref);
2813     if (code >= 0 && !r_has_type(pref, t_null)) {
2814         if (!r_is_array(pref))
2815             return_error(e_typecheck);
2816         if (r_size(pref) != 3)
2817             return_error(e_rangecheck);
2818 
2819         for (i=0;i<3;i++) {
2820             code = array_get(imemory, pref, i, &valref);
2821             if (code < 0)
2822                 return code;
2823             check_proc(valref);
2824         }
2825     }
2826 
2827     code = dict_find_string(&CIEdict, "RangeHIJ", &pref);
2828     if (code >= 0 && !r_has_type(pref, t_null)) {
2829         if (!r_is_array(pref))
2830             return_error(e_typecheck);
2831         if (r_size(pref) != 6)
2832             return_error(e_rangecheck);
2833 
2834         for (i=0;i<6;i++) {
2835             code = array_get(imemory, pref, i, &valref);
2836             if (code < 0)
2837                 return code;
2838             if (r_has_type(&valref, t_integer))
2839                 value[i] = (float)valref.value.intval;
2840             else if (r_has_type(&valref, t_real))
2841                 value[i] = (float)valref.value.realval;
2842             else
2843                 return_error(e_typecheck);
2844         }
2845         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4])
2846             return_error(e_rangecheck);
2847     }
2848 
2849     *r = 0;
2850     return 0;
2851 }
ciedefdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)2852 static int ciedefdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2853 {
2854     int i, code;
2855     ref     CIEdict, *tempref, valref;
2856 
2857     code = array_get(imemory, space, 1, &CIEdict);
2858     if (code < 0)
2859         return code;
2860 
2861     /* If we have a RangeDEF, get the values from that */
2862     code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2863     if (code >= 0 && !r_has_type(tempref, t_null)) {
2864         for (i=0;i<6;i++) {
2865             code = array_get(imemory, tempref, i, &valref);
2866             if (code < 0)
2867                 return code;
2868             if (r_has_type(&valref, t_integer))
2869                 ptr[i] = (float)valref.value.intval;
2870             else if (r_has_type(&valref, t_real))
2871                 ptr[i] = (float)valref.value.realval;
2872             else
2873                 return_error(e_typecheck);
2874         }
2875     } else {
2876         /* Default values for a CIEBasedDEF */
2877         for (i=0;i<3;i++) {
2878             ptr[2 * i] = 0;
2879             ptr[(2 * i) + 1] = 1;
2880         }
2881     }
2882     return 0;
2883 }
ciedefrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)2884 static int ciedefrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
2885 {
2886     int i, code;
2887     ref     CIEdict, *tempref, valref;
2888 
2889     code = array_get(imemory, space, 1, &CIEdict);
2890     if (code < 0)
2891         return code;
2892 
2893     /* If we have a RangeDEF, get the values from that */
2894     code = dict_find_string(&CIEdict, "RangeDEF", &tempref);
2895     if (code >= 0 && !r_has_type(tempref, t_null)) {
2896         for (i=0;i<6;i++) {
2897             code = array_get(imemory, tempref, i, &valref);
2898             if (code < 0)
2899                 return code;
2900             if (r_has_type(&valref, t_integer))
2901                 ptr[i] = (float)valref.value.intval;
2902             else if (r_has_type(&valref, t_real))
2903                 ptr[i] = (float)valref.value.realval;
2904             else
2905                 return_error(e_typecheck);
2906         }
2907     } else {
2908         /* Default values for a CIEBasedDEF */
2909         for (i=0;i<3;i++) {
2910             ptr[2 * i] = 0;
2911             ptr[(2 * i) + 1] = 1;
2912         }
2913     }
2914     return 0;
2915 }
ciedefvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)2916 static int ciedefvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
2917 {
2918     os_ptr op = osp;
2919     int i;
2920 
2921     if (num_comps < 3)
2922         return_error(e_stackunderflow);
2923 
2924     op -= 2;
2925     for (i=0;i<3;i++) {
2926         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
2927             return_error(e_typecheck);
2928         op++;
2929     }
2930 
2931     return 0;
2932 }
ciedefcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)2933 static int ciedefcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
2934 {
2935     int code = 0;
2936     ref CIEdict1, CIEdict2;
2937 
2938     code = array_get(imemory, space, 1, &CIEdict1);
2939     if (code < 0)
2940         return 0;
2941     code = array_get(imemory, testspace, 1, &CIEdict2);
2942     if (code < 0)
2943         return 0;
2944     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
2945         return 0;
2946     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
2947         return 0;
2948     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
2949         return 0;
2950     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
2951         return 0;
2952     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
2953         return 0;
2954     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
2955         return 0;
2956     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
2957         return 0;
2958     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
2959         return 0;
2960     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEF"))
2961         return 0;
2962     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEF"))
2963         return 0;
2964     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJ"))
2965         return 0;
2966     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
2967         return 0;
2968     return 1;
2969 }
2970 
2971 /* CIEBasedDEFG */
setciedefgspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)2972 static int setciedefgspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
2973 {
2974     int code = 0;
2975     ref CIEDict, *nocie;
2976     ulong dictkey;
2977 
2978     if (i_ctx_p->language_level < 3)
2979         return_error(e_undefined);
2980 
2981     code = dict_find_string(systemdict, "NOCIE", &nocie);
2982     if (code < 0)
2983         return code;
2984     if (!r_has_type(nocie, t_boolean))
2985         return_error(e_typecheck);
2986     if (nocie->value.boolval)
2987         return setcmykspace(i_ctx_p, r, stage, cont, 1);
2988 
2989     *cont = 0;
2990     code = array_get(imemory, r, 1, &CIEDict);
2991     if (code < 0)
2992         return code;
2993     if ((*stage) > 0) {
2994         gs_client_color cc;
2995         int i;
2996 
2997         cc.pattern = 0x00;
2998         for (i=0;i<4;i++)
2999             cc.paint.values[i] = 0;
3000         code = gs_setcolor(igs, &cc);
3001         *stage = 0;
3002         return code;
3003     }
3004     dictkey = r->value.refs->value.saveid;
3005     code = ciedefgspace(i_ctx_p, &CIEDict,dictkey);
3006     *cont = 1;
3007     (*stage)++;
3008     return code;
3009 }
validateciedefgspace(i_ctx_t * i_ctx_p,ref ** r)3010 static int validateciedefgspace(i_ctx_t * i_ctx_p, ref **r)
3011 {
3012     int code = 0, i, j;
3013     float value[8];
3014     ref     CIEdict, *CIEspace = *r, tempref, arrayref, valref, *pref = &tempref;
3015 
3016     if (!r_is_array(CIEspace))
3017         return_error(e_typecheck);
3018     /* Validate parameters, check we have enough operands */
3019     if (r_size(CIEspace) != 2)
3020         return_error(e_rangecheck);
3021 
3022     code = array_get(imemory, CIEspace, 1, &CIEdict);
3023     if (code < 0)
3024         return code;
3025     check_read_type(CIEdict, t_dictionary);
3026 
3027     code = validatecieabcspace(i_ctx_p, r);
3028     if (code != 0)
3029         return code;
3030 
3031     code = dict_find_string(&CIEdict, "Table", &pref);
3032     if (code >= 0) {
3033         if (!r_is_array(pref))
3034             return_error(e_typecheck);
3035         if (r_size(pref) != 5)
3036             return_error(e_rangecheck);
3037 
3038         for (i=0;i<4;i++) {
3039             code = array_get(imemory, pref, i, &valref);
3040             if (code < 0)
3041                 return code;
3042             if (r_has_type(&valref, t_integer))
3043                 value[i] = (float)valref.value.intval;
3044             else
3045                 return_error(e_typecheck);
3046         }
3047         if (value[0] <= 1 || value[1] <= 1 || value[2] <= 1 || value[3] <= 1)
3048             return_error(e_rangecheck);
3049 
3050         code = array_get(imemory, pref, 4, &arrayref);
3051         if (code < 0)
3052             return code;
3053         if (!r_is_array(&arrayref))
3054             return_error(e_typecheck);
3055         if (r_size(&arrayref) != value[0])
3056             return_error(e_rangecheck);
3057 
3058         for (i=0;i<value[0];i++) {
3059             code = array_get(imemory, &arrayref, i, &tempref);
3060             if (code < 0)
3061                 return code;
3062             for (j=0;j<value[1];j++) {
3063                 code = array_get(imemory, &tempref, i, &valref);
3064                 if (code < 0)
3065                     return code;
3066                 if (!r_has_type(&valref, t_string))
3067                     return_error(e_typecheck);
3068 
3069                 if (r_size(&valref) != (3 * value[2] * value[3]))
3070                     return_error(e_rangecheck);
3071             }
3072         }
3073     } else {
3074         return_error(e_rangecheck);
3075     }
3076 
3077     /* Remaining parameters are optional, but we must validate
3078      * them if they are present
3079      */
3080     code = dict_find_string(&CIEdict, "RangeDEFG", &pref);
3081     if (code >= 0 && !r_has_type(pref, t_null)) {
3082         if (!r_is_array(pref))
3083             return_error(e_typecheck);
3084         if (r_size(pref) != 8)
3085             return_error(e_rangecheck);
3086 
3087         for (i=0;i<8;i++) {
3088             code = array_get(imemory, pref, i, &valref);
3089             if (code < 0)
3090                 return code;
3091             if (r_has_type(&valref, t_integer))
3092                 value[i] = (float)valref.value.intval;
3093             else if (r_has_type(&valref, t_real))
3094                 value[i] = (float)valref.value.realval;
3095             else
3096                 return_error(e_typecheck);
3097         }
3098         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3099             return_error(e_rangecheck);
3100     }
3101 
3102     code = dict_find_string(&CIEdict, "DecodeDEFG", &pref);
3103     if (code >= 0 && !r_has_type(pref, t_null)) {
3104         if (!r_is_array(pref))
3105             return_error(e_typecheck);
3106         if (r_size(pref) != 4)
3107             return_error(e_rangecheck);
3108 
3109         for (i=0;i<4;i++) {
3110             code = array_get(imemory, pref, i, &valref);
3111             if (code < 0)
3112                 return code;
3113             check_proc(valref);
3114         }
3115     }
3116 
3117     code = dict_find_string(&CIEdict, "RangeHIJK", &pref);
3118     if (code >= 0 && !r_has_type(pref, t_null)) {
3119         if (!r_is_array(pref))
3120             return_error(e_typecheck);
3121         if (r_size(pref) != 8)
3122             return_error(e_rangecheck);
3123 
3124         for (i=0;i<8;i++) {
3125             code = array_get(imemory, pref, i, &valref);
3126             if (code < 0)
3127                 return code;
3128             if (r_has_type(&valref, t_integer))
3129                 value[i] = (float)valref.value.intval;
3130             else if (r_has_type(&valref, t_real))
3131                 value[i] = (float)valref.value.realval;
3132             else
3133                 return_error(e_typecheck);
3134         }
3135         if (value[1] < value[0] || value[3] < value[2] || value[5] < value[4] || value[7] < value[6])
3136             return_error(e_rangecheck);
3137     }
3138 
3139     *r = 0;
3140     return 0;
3141 }
ciedefgdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)3142 static int ciedefgdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3143 {
3144     int i, code;
3145     ref     CIEdict, *tempref, valref;
3146 
3147     code = array_get(imemory, space, 1, &CIEdict);
3148     if (code < 0)
3149         return code;
3150 
3151     /* If we have a RangeDEFG, get the values from that */
3152     code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3153     if (code >= 0 && !r_has_type(tempref, t_null)) {
3154         for (i=0;i<8;i++) {
3155             code = array_get(imemory, tempref, i, &valref);
3156             if (code < 0)
3157                 return code;
3158             if (r_has_type(&valref, t_integer))
3159                 ptr[i] = (float)valref.value.intval;
3160             else if (r_has_type(&valref, t_real))
3161                 ptr[i] = (float)valref.value.realval;
3162             else
3163                 return_error(e_typecheck);
3164         }
3165     } else {
3166         /* Default values for a CIEBasedDEFG */
3167         for (i=0;i<4;i++) {
3168             ptr[2 * i] = 0;
3169             ptr[(2 * i) + 1] = 1;
3170         }
3171     }
3172     return 0;
3173 }
ciedefgrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)3174 static int ciedefgrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3175 {
3176     int i, code;
3177     ref     CIEdict, *tempref, valref;
3178 
3179     code = array_get(imemory, space, 1, &CIEdict);
3180     if (code < 0)
3181         return code;
3182 
3183     /* If we have a RangeDEFG, get the values from that */
3184     code = dict_find_string(&CIEdict, "RangeDEFG", &tempref);
3185     if (code >= 0 && !r_has_type(tempref, t_null)) {
3186         for (i=0;i<8;i++) {
3187             code = array_get(imemory, tempref, i, &valref);
3188             if (code < 0)
3189                 return code;
3190             if (r_has_type(&valref, t_integer))
3191                 ptr[i] = (float)valref.value.intval;
3192             else if (r_has_type(&valref, t_real))
3193                 ptr[i] = (float)valref.value.realval;
3194             else
3195                 return_error(e_typecheck);
3196         }
3197     } else {
3198         /* Default values for a CIEBasedDEFG */
3199         for (i=0;i<4;i++) {
3200             ptr[2 * i] = 0;
3201             ptr[(2 * i) + 1] = 1;
3202         }
3203     }
3204     return 0;
3205 }
ciedefgvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)3206 static int ciedefgvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3207 {
3208     os_ptr op = osp;
3209     int i;
3210 
3211     if (num_comps < 4)
3212         return_error(e_stackunderflow);
3213 
3214     op -= 3;
3215     for (i=0;i < 4;i++) {
3216         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3217             return_error(e_typecheck);
3218         op++;
3219     }
3220     return 0;
3221 }
ciedefgcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)3222 static int ciedefgcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3223 {
3224     /* If the problems mentioned above are resolved, then this code could
3225      * be re-instated.
3226      */
3227     int code = 0;
3228     ref CIEdict1, CIEdict2;
3229 
3230     code = array_get(imemory, space, 1, &CIEdict1);
3231     if (code < 0)
3232         return 0;
3233     code = array_get(imemory, testspace, 1, &CIEdict2);
3234     if (code < 0)
3235         return 0;
3236     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"WhitePoint"))
3237         return 0;
3238     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"BlackPoint"))
3239         return 0;
3240     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeABC"))
3241         return 0;
3242     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeABC"))
3243         return 0;
3244     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixABC"))
3245         return 0;
3246     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeLMN"))
3247         return 0;
3248     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeLMN"))
3249         return 0;
3250     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"MatrixMN"))
3251         return 0;
3252     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeDEFG"))
3253         return 0;
3254     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"DecodeDEFG"))
3255         return 0;
3256     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"RangeHIJK"))
3257         return 0;
3258     if (!comparedictkey(i_ctx_p, &CIEdict1, &CIEdict2, (char *)"Table"))
3259         return 0;
3260     return 1;
3261 }
3262 
3263 static char const * const CIESpaces[] = {
3264     "CIEBasedA",
3265     "CIEBasedABC",
3266     "CIEBasedDEF",
3267     "CIEBasedDEFG"
3268 };
3269 /* This routine returns the Device space equivalents for a CIEBased space.
3270  * Used by currentgray, currentrgb and currentcmyk, the PLRM says that CIE
3271  * spaces return 0 for all components.
3272  */
ciebasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)3273 static int ciebasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3274 {
3275     os_ptr op;
3276     ref *spacename, nref;
3277     int i, components=1, code;
3278 
3279     /* If the spaece is an array, the first element is always the name */
3280     if (r_is_array(space))
3281         spacename = space->value.refs;
3282     else
3283         spacename = space;
3284     /* Check that it really is a name */
3285     if (!r_has_type(spacename, t_name))
3286         return_error(e_typecheck);
3287 
3288     /* Find the relevant color space object */
3289     for (i=0;i<4;i++) {
3290         code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)CIESpaces[i], strlen(CIESpaces[i]), &nref, 0);
3291         if (code < 0)
3292             return code;
3293         if (name_eq(spacename, &nref)) {
3294             break;
3295         }
3296     }
3297     /* Find out how many values are on the stack, which depends
3298      * on what kind of CIEBased space this is.
3299      */
3300     switch(i){
3301         case 0:
3302             components = 1;
3303             break;
3304         case 1:
3305         case 2:
3306             components = 3;
3307             break;
3308         case 3:
3309             components = 4;
3310             break;
3311     }
3312     /* Remove teh requisite number of values */
3313     pop(components);
3314     op = osp;
3315     /* Find out how many values we need to return, which
3316      * depends on the requested space.
3317      */
3318     switch(base) {
3319         case 0:
3320             components = 1;
3321             break;
3322         case 1:
3323         case 2:
3324             components = 3;
3325             break;
3326         case 3:
3327             components = 4;
3328             break;
3329     }
3330     push(components);
3331     /* The PLRM says that all the components should be returned as 0.0 */
3332     op -= components-1;
3333     for (i=0;i<components;i++) {
3334         make_real(op, (float)0);
3335         op++;
3336     }
3337     /* However, Adobe implementations actually return 1.0 for the black
3338      * channel of CMYK...
3339      */
3340     if (components == 4) {
3341         op--;
3342         make_real(op, (float)1);
3343     }
3344     *stage = 0;
3345     *cont = 0;
3346     return 0;
3347 }
3348 
3349 /* This routine used by both Separatin and DeviceN spaces to convert
3350  * a PostScript tint transform into a Function, either a type 4
3351  * 'PostScript calculator (see PDF reference) or a type 0 'sampled'
3352  * function.
3353  */
convert_transform(i_ctx_t * i_ctx_p,ref * arr,ref * pproc)3354 static int convert_transform(i_ctx_t * i_ctx_p, ref *arr, ref *pproc)
3355 {
3356     os_ptr op = osp;   /* required by "push" macro */
3357     int code;
3358 
3359     /* buildfunction returns an operand on the stack. In fact
3360      * it replaces the lowest operand, so make sure there is an
3361      * empty sacrificial one present.
3362      */
3363     push(1);
3364     /* Start by trying a type 4 function */
3365     code = buildfunction(i_ctx_p, arr, pproc, 4);
3366 
3367     if (code < 0)
3368         /* If that fails, try a type 0. We prefer a type 4
3369          * because a type 0 will require us to sample the
3370          * space, which is expensive
3371          */
3372         code = buildfunction(i_ctx_p, arr, pproc, 0);
3373 
3374     return code;
3375 }
3376 
3377 /* Separation */
setseparationspace(i_ctx_t * i_ctx_p,ref * sepspace,int * stage,int * cont,int CIESubst)3378 static int setseparationspace(i_ctx_t * i_ctx_p, ref *sepspace, int *stage, int *cont, int CIESubst)
3379 {
3380     os_ptr op = osp;   /* required by "push" macro */
3381     int code = 0;
3382     ref sname, proc;
3383     ref name_none, name_all;
3384     separation_type sep_type;
3385     ref_colorspace cspace_old;
3386     gs_color_space *pcs;
3387     gs_color_space * pacs;
3388     gs_function_t *pfn = NULL;
3389     gs_client_color cc;
3390 
3391     if (i_ctx_p->language_level < 2)
3392         return_error(e_undefined);
3393 
3394     *cont = 0;
3395     if ((*stage) == 0) {
3396         code = array_get(imemory, sepspace, 3, &proc);
3397         if (code < 0)
3398             return code;
3399         /* Check to see if we already have a function (eg from a PDF file) */
3400         pfn = ref_function(&proc);
3401         if (pfn == NULL) {
3402             /* Convert tint transform to a PostScript function */
3403             code = convert_transform(i_ctx_p, sepspace, &proc);
3404             if (code < 0)
3405                 return code;
3406             if (code > 0) {
3407                 *cont = 1;
3408                 (*stage)++;
3409                 return code;
3410             }
3411             /* We can only get here if the transform converted to a function
3412              * without requiring a continuation. Most likely this means its a
3413              * type 4 function. If so then it is still on the stack.
3414              */
3415             op = osp;
3416             pfn = ref_function(op);
3417             pop (1);
3418         }
3419     } else {
3420         /* The function is returned on the operand stack */
3421         op = osp;
3422         pfn = ref_function(op);
3423         pop (1);
3424     }
3425 
3426     *stage = 0;
3427     if ((code = name_ref(imemory, (const byte *)"All", 3, &name_all, 0)) < 0)
3428         return code;
3429     if ((code = name_ref(imemory, (const byte *)"None", 4, &name_none, 0)) < 0)
3430         return code;
3431     /* Check separation name is a string or name object */
3432     code = array_get(imemory, sepspace, 1, &sname);
3433     if (code < 0)
3434         return code;
3435 
3436     if (r_has_type(&sname, t_string)) {
3437         code = name_from_string(imemory, &sname, &sname);
3438         if (code < 0)
3439             return code;
3440     }
3441     sep_type = ( name_eq(&sname, &name_all) ? SEP_ALL :
3442                  name_eq(&sname, &name_none) ? SEP_NONE : SEP_OTHER);
3443 
3444     /* The alternate color space has been selected as the current color space */
3445     pacs = gs_currentcolorspace(igs);
3446 
3447     cspace_old = istate->colorspace[0];
3448     /* Now set the current color space as Separation */
3449     code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3450     if (code < 0)
3451         return code;
3452     pcs->params.separation.sep_type = sep_type;
3453     pcs->params.separation.sep_name = name_index(imemory, &sname);
3454     pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3455     code = array_get(imemory, sepspace, 1, &proc);
3456     if (code < 0)
3457         return code;
3458     istate->colorspace[0].procs.special.separation.layer_name = proc;
3459     code = array_get(imemory, sepspace, 3, &proc);
3460     if (code < 0)
3461         return code;
3462     istate->colorspace[0].procs.special.separation.tint_transform = proc;
3463     if (code >= 0)
3464         code = gs_cspace_set_sepr_function(pcs, pfn);
3465     if (code >= 0)
3466         code = gs_setcolorspace(igs, pcs);
3467     /* release reference from construction */
3468     rc_decrement_only_cs(pcs, "setseparationspace");
3469     if (code < 0) {
3470         istate->colorspace[0] = cspace_old;
3471         return code;
3472     }
3473     cc.pattern = 0x00;
3474     cc.paint.values[0] = 1.0;
3475     code = gs_setcolor(igs, &cc);
3476     return code;
3477 }
validateseparationspace(i_ctx_t * i_ctx_p,ref ** space)3478 static int validateseparationspace(i_ctx_t * i_ctx_p, ref **space)
3479 {
3480     int code = 0;
3481     ref *sepspace = *space;
3482     ref nameref, sref, sname, altspace, tref;
3483 
3484     if (!r_is_array(sepspace))
3485         return_error(e_typecheck);
3486     /* Validate parameters, check we have enough operands */
3487     if (r_size(sepspace) != 4)
3488         return_error(e_rangecheck);
3489 
3490     /* Check separation name is a string or name object */
3491     code = array_get(imemory, sepspace, 1, &sname);
3492     if (code < 0)
3493         return code;
3494     if (!r_has_type(&sname, t_name)) {
3495         if (!r_has_type(&sname, t_string))
3496             return_error(e_typecheck);
3497         else {
3498             code = name_from_string(imemory, &sname, &sname);
3499             if (code < 0)
3500                 return code;
3501         }
3502     }
3503 
3504     /* Check the tint transform is a procedure */
3505     code = array_get(imemory, sepspace, 3, &tref);
3506     if (code < 0)
3507         return code;
3508     check_proc(tref);
3509 
3510     /* Get the name of the alternate space */
3511     code = array_get(imemory, sepspace, 2, &altspace);
3512     if (code < 0)
3513         return code;
3514     if (r_has_type(&altspace, t_name))
3515         ref_assign(&nameref, &altspace);
3516     else {
3517         /* Make sure the alternate space is an array */
3518         if (!r_is_array(&altspace))
3519             return_error(e_typecheck);
3520         /* And has a name for its type */
3521         code = array_get(imemory, &altspace, 0, &tref);
3522         if (code < 0)
3523             return code;
3524         if (!r_has_type(&tref, t_name))
3525             return_error(e_typecheck);
3526         ref_assign(&nameref, &tref);
3527     }
3528 
3529     /* Convert alternate space name to string */
3530     name_string_ref(imemory, &nameref, &sref);
3531     /* Check its not /Indexed or /Pattern or /DeviceN */
3532     if (r_size(&sref) == 7) {
3533         if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
3534             return_error(e_typecheck);
3535         if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
3536             return_error(e_typecheck);
3537         if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
3538             return_error(e_typecheck);
3539     }
3540     /* and also not /Separation */
3541     if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
3542         return_error(e_typecheck);
3543 
3544     ref_assign(*space, &altspace);
3545     return 0;
3546 }
separationalternatespace(i_ctx_t * i_ctx_p,ref * sepspace,ref ** r,int * CIESubst)3547 static int separationalternatespace(i_ctx_t * i_ctx_p, ref *sepspace, ref **r, int *CIESubst)
3548 {
3549     ref tref;
3550     int code;
3551 
3552     code = array_get(imemory, sepspace, 2, &tref);
3553     if (code < 0)
3554         return code;
3555     ref_assign(*r, &tref);
3556     return 0;
3557 }
sepdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)3558 static int sepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3559 {
3560     ptr[0] = 0;
3561     ptr[1] = 1;
3562     return 0;
3563 }
seprange(i_ctx_t * i_ctx_p,ref * space,float * ptr)3564 static int seprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
3565 {
3566     ptr[0] = 0;
3567     ptr[1] = 1;
3568     return 0;
3569 }
septransform(i_ctx_t * i_ctx_p,ref * sepspace,int * usealternate,int * stage,int * stack_depth)3570 static int septransform(i_ctx_t *i_ctx_p, ref *sepspace, int *usealternate, int *stage, int *stack_depth)
3571 {
3572     gx_device * dev = igs->device;
3573     ref sname, proc;
3574     int code, colorant_number;
3575 
3576     code = array_get(imemory, sepspace, 1, &sname);
3577     if (code < 0)
3578         return code;
3579     if (r_has_type(&sname, t_name)) {
3580         name_string_ref(imemory, &sname, &sname);
3581     }
3582 
3583     /* Check for /All and /None, never need the alternate for these */
3584     if (r_size(&sname) == 3 &&
3585         strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3586         *usealternate = 0;
3587         return 0;
3588     }
3589     if (r_size(&sname) == 4 &&
3590         strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0) {
3591         *usealternate = 0;
3592         return 0;
3593     }
3594     /*
3595      * Compare the colorant name to the device's.  If the device's
3596      * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
3597      * colorant is in the SeparationNames list but not in the
3598      * SeparationOrder list.
3599      */
3600     colorant_number = (*dev_proc(dev, get_color_comp_index))
3601                 (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
3602     if (colorant_number >= 0) {		/* If valid colorant name */
3603         *usealternate = 0;
3604     } else
3605         *usealternate = 1;
3606 
3607     if (*usealternate && *stage == 0) {
3608         (*stage)++;
3609         esp++;
3610         code = array_get(imemory, sepspace, 3, &proc);
3611         if (code < 0)
3612             return code;
3613         *esp = proc;
3614         return o_push_estack;
3615     }
3616     *stage = 0;
3617     return 0;
3618 }
sepbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)3619 static int sepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
3620 {
3621     os_ptr op = osp;   /* required by "push" macro */
3622     int use, code;
3623 
3624         code = septransform(i_ctx_p, space, &use, stage, stack_depth);
3625         if (code != 0)
3626             return code;
3627         if (!use) {
3628             *stage = 0;
3629             *cont = 0;
3630             pop(1);
3631             op = osp;
3632             switch(base) {
3633                 case 0:
3634                     push(1);
3635                     make_real(op, 0.0);
3636                     break;
3637                 case 1:
3638                 case 2:
3639                     push(3);
3640                     make_real(&op[-2], 0.0);
3641                     make_real(&op[-1], 0.0);
3642                     make_real(op, 0.0);
3643                     break;
3644                 case 3:
3645                     push(4);
3646                     make_real(&op[-3], 0.0);
3647                     make_real(&op[-2], 0.0);
3648                     make_real(&op[-1], 0.0);
3649                     make_real(op, 0.0);
3650                     break;
3651             }
3652         } else {
3653             *stage = 0;
3654             *cont = 1;
3655         }
3656     return 0;
3657 }
sepvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)3658 static int sepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
3659 {
3660     os_ptr op = osp;
3661 
3662     if (num_comps < 1)
3663         return_error(e_stackunderflow);
3664 
3665     if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
3666         return_error(e_typecheck);
3667 
3668     if (*values > 1.0)
3669         *values = 1.0;
3670 
3671     if (*values < 0.0)
3672         *values = 0.0;
3673 
3674     return 0;
3675 }
sepcompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)3676 static int sepcompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
3677 {
3678     ref sname1, sname2;
3679     int code;
3680 
3681     code = array_get(imemory, space, 1, &sname1);
3682     if (code < 0)
3683         return 0;
3684 
3685     code = array_get(imemory, testspace, 1, &sname2);
3686     if (code < 0)
3687         return 0;
3688 
3689     if (r_type(&sname1) != r_type(&sname2))
3690         return 0;
3691 
3692     switch(r_type(&sname1)) {
3693         case t_name:
3694             if (!name_eq(&sname1, &sname2))
3695                 return 0;
3696             break;
3697         case t_string:
3698             if (r_size(&sname1) != r_size(&sname2))
3699                 return 0;
3700             if (strncmp((const char *)sname1.value.const_bytes, (const char *)sname2.value.const_bytes, r_size(&sname1)) != 0)
3701                 return 0;
3702             break;
3703         default:
3704             return 0;
3705     }
3706     code = array_get(imemory, testspace, 2, &sname1);
3707     if (code < 0)
3708         return 0;
3709     code = array_get(imemory, testspace, 2, &sname2);
3710     if (code < 0)
3711         return 0;
3712     if (r_type(&sname1) != r_type(&sname2))
3713         return 0;
3714 
3715     if (r_is_array(&sname1)) {
3716         if (!comparearrays(i_ctx_p, &sname1, &sname2))
3717             return 0;
3718     } else {
3719         if (!r_has_type(&sname1, t_name))
3720             return 0;
3721         if (!name_eq(&sname1, &sname2))
3722             return 0;
3723     }
3724     code = array_get(imemory, space, 3, &sname1);
3725     if (code < 0)
3726         return 0;
3727     code = array_get(imemory, testspace, 3, &sname2);
3728     if (code < 0)
3729         return 0;
3730     return(comparearrays(i_ctx_p, &sname1, &sname2));
3731 }
sepinitialproc(i_ctx_t * i_ctx_p,ref * space)3732 static int sepinitialproc(i_ctx_t *i_ctx_p, ref *space)
3733 {
3734     gs_client_color cc;
3735 
3736     cc.pattern = 0x00;
3737     cc.paint.values[0] = 1.0;
3738     return gs_setcolor(igs, &cc);
3739 }
3740 
3741 /* DeviceN */
devicencolorants_cont(i_ctx_t * i_ctx_p)3742 static int devicencolorants_cont(i_ctx_t *i_ctx_p)
3743 {
3744     ref dict, *pdict = &dict, space[2], sname;
3745     int index, code, depth, stage;
3746     es_ptr ep = esp, pindex, pstage;
3747     os_ptr op = osp;
3748     gs_separation_name sep_name;
3749 
3750     pindex = &ep[-2];
3751     pstage = &ep[-1];
3752     index = (int)pindex->value.intval;
3753     stage = (int)pstage->value.intval;
3754     ref_assign(&dict, ep);
3755 
3756     do {
3757         if (index >= dict_length(pdict)) {
3758             esp -= 4;
3759             return o_pop_estack;
3760         }
3761 
3762         if (stage == 0) {
3763             code = gs_gsave(igs);
3764             if (code < 0)
3765                 return code;
3766 
3767             code = dict_index_entry(pdict, index, (ref *)&space);
3768             if (code < 0) {
3769                 make_int(pindex, ++index);
3770                 code = gs_grestore(igs);
3771                 if (code < 0)
3772                     return code;
3773                 continue;
3774             }
3775 
3776             code = validate_spaces(i_ctx_p, &space[1], &depth);
3777             if (code < 0) {
3778                 make_int(pindex, ++index);
3779                 code = gs_grestore(igs);
3780                 if (code < 0)
3781                     return code;
3782                 return o_push_estack;
3783             }
3784 
3785             /* If we get a continuation from a sub-procedure, we will want to come back
3786              * here afterward, to do any remaining stages. We need to set up for that now.
3787              * so that our continuation is ahead of the sub-proc's continuation.
3788              */
3789             check_estack(1);
3790             push(1);
3791             /* The push_op_estack macro increments esp before use, so we don't need to */
3792             push_op_estack(devicencolorants_cont);
3793 
3794             make_int(pstage, 1);
3795             *op = space[1];
3796             code = zsetcolorspace(i_ctx_p);
3797             if (code != 0)
3798                 return code;
3799         } else {
3800             stage = 0;
3801             code = dict_index_entry(pdict, index, (ref *)&space);
3802             if (code == 0) {
3803                 switch (r_type(&space[0])) {
3804                     case t_string:
3805                         code = name_from_string(imemory, &space[0], &sname);
3806                         if (code == 0)
3807                             sep_name = name_index(imemory, &sname);
3808                         break;
3809                     case t_name:
3810                         sep_name = name_index(imemory, &space[0]);
3811                         break;
3812                     default:
3813                         code = e_typecheck;
3814                 }
3815             }
3816             make_int(pindex, ++index);
3817             make_int(pstage, stage);
3818             if (code == 0)
3819                 gs_attachattributecolorspace(sep_name, igs);
3820             code = gs_grestore(igs);
3821             if (code < 0)
3822                 return code;
3823         }
3824     }
3825     while(1);
3826 }
3827 
setdevicenspace(i_ctx_t * i_ctx_p,ref * devicenspace,int * stage,int * cont,int CIESubst)3828 static int setdevicenspace(i_ctx_t * i_ctx_p, ref *devicenspace, int *stage, int *cont, int CIESubst)
3829 {
3830     os_ptr  op = osp;   /* required by "push" macro */
3831     int code = 0, num_components, i;
3832     ref namesarray, proc, sname, tname, sref, tempref[2];
3833     ref_colorspace cspace_old;
3834     gs_color_space *pcs;
3835     gs_color_space * pacs;
3836     gs_function_t *pfn = NULL;
3837     gs_separation_name *names;
3838     gs_device_n_map *pmap;
3839     gs_client_color cc;
3840 
3841     if (i_ctx_p->language_level < 3)
3842         return_error(e_undefined);
3843 
3844     *cont = 0;
3845     if ((*stage) == 2) {
3846         if (r_size(devicenspace) == 5) {
3847             /* We have a Colorants dictionary from a PDF file. We need to handle this by
3848              * temporarily setting each of the spaces in the dict, and attaching the
3849              * resulting space to the DeviceN array. This is complicated, because
3850              * each space must be fully set up, and may result in running tint transform
3851              * procedures and caching results. We need to handle this in yet another
3852              * layering of continuation procedures.
3853              */
3854             code = array_get(imemory, devicenspace, 4, &sref);
3855             if (code < 0)
3856                 return code;
3857             if (!r_has_type(&sref, t_dictionary)) {
3858                 *stage = 0;
3859                 return 0;
3860             }
3861             if (dict_length(&sref) == 0)
3862                 return(0);
3863 
3864             code = dict_index_entry(&sref, 0, (ref *)&tempref);
3865             if (code < 0)
3866                 return code;
3867             name_string_ref(imemory, &tempref[0], &sname);
3868             if (r_size(&sname) != 9 || strncmp((const char *)sname.value.const_bytes, "Colorants", r_size(&sname)) != 0) {
3869                 *stage = 0;
3870                 return 0;
3871             }
3872 
3873             *stage = 3;
3874             *cont = 1;
3875             check_estack(5);
3876             push_mark_estack(es_other, colour_cleanup);
3877             esp++;
3878             /* variable to hold index of the space we are dealing with */
3879             make_int(esp, 0);
3880             esp++;
3881             /* variable to hold processing step */
3882             make_int(esp, 0);
3883             esp++;
3884             /* Store a pointer to the Colorants dictionary
3885              */
3886             ref_assign(esp, &tempref[1]);
3887             push_op_estack(devicencolorants_cont);
3888             return o_push_estack;
3889         } else {
3890             *stage = 0;
3891             return 0;
3892         }
3893     }
3894     if ((*stage) == 3) {
3895         *stage = 0;
3896         return 0;
3897     }
3898     if ((*stage) == 0) {
3899         code = array_get(imemory, devicenspace, 3, &proc);
3900         if (code < 0)
3901             return code;
3902         pfn = ref_function(&proc);
3903         if (pfn == NULL) {
3904             /* Convert tint transform to a PostScript function */
3905             code = convert_transform(i_ctx_p, devicenspace, &proc);
3906             if (code < 0)
3907                 return code;
3908             if (code > 0) {
3909                 *cont = 1;
3910                 *stage = 1;
3911                 return code;
3912             }
3913             /* We can only get here if the transform converted to a function
3914              * without requiring a continuation. Most likely this means its a
3915              * type 4 function. If so then it is still on the stack.
3916              */
3917             op = osp;
3918             pfn = ref_function(op);
3919             pop (1);
3920         }
3921     } else {
3922         /* The function is returned on the operand stack */
3923         op = osp;
3924         pfn = ref_function(op);
3925         pop (1);
3926     }
3927 
3928     *stage = 2;
3929 
3930     code = array_get(imemory, devicenspace, 1, &namesarray);
3931     if (code < 0)
3932         return code;
3933     num_components = r_size(&namesarray);
3934     /* The alternate color space has been selected as the current color space */
3935     pacs = gs_currentcolorspace(igs);
3936 
3937     if (num_components == 1) {
3938         array_get(imemory, &namesarray, (long)0, &sname);
3939         switch (r_type(&sname)) {
3940             case t_string:
3941                 tname = sname;
3942                 break;
3943             case t_name:
3944                 name_string_ref(imemory, &sname, &tname);
3945                 break;
3946             default:
3947                 return_error(e_typecheck);
3948                 break;
3949         }
3950         if (strncmp((const char *)tname.value.const_bytes, "All", 3) == 0 && r_size(&tname) == 3) {
3951             separation_type sep_type;
3952 
3953             /* Sigh, Acrobat allows this, even though its contra the spec. Convert to
3954              * a /Separation space and go on
3955              */
3956             sep_type = SEP_ALL;
3957 
3958             /* The alternate color space has been selected as the current color space */
3959             pacs = gs_currentcolorspace(igs);
3960 
3961             cspace_old = istate->colorspace[0];
3962             /* Now set the current color space as Separation */
3963             code = gs_cspace_new_Separation(&pcs, pacs, imemory);
3964             if (code < 0)
3965                 return code;
3966             pcs->params.separation.sep_type = sep_type;
3967             pcs->params.separation.sep_name = name_index(imemory, &sname);
3968             pcs->params.separation.get_colorname_string = gs_get_colorname_string;
3969             code = array_get(imemory, &namesarray, (long)0, &sname);
3970             if (code < 0)
3971                 return code;
3972             istate->colorspace[0].procs.special.separation.layer_name = sname;
3973             code = array_get(imemory, devicenspace, 3, &proc);
3974             if (code < 0)
3975                 return code;
3976             istate->colorspace[0].procs.special.separation.tint_transform = proc;
3977             if (code >= 0)
3978                 code = gs_cspace_set_sepr_function(pcs, pfn);
3979             if (code >= 0)
3980                 code = gs_setcolorspace(igs, pcs);
3981             /* release reference from construction */
3982             rc_decrement_only_cs(pcs, "setseparationspace");
3983             if (code < 0) {
3984                 istate->colorspace[0] = cspace_old;
3985                 return code;
3986             }
3987             cc.pattern = 0x00;
3988             cc.paint.values[0] = 1.0;
3989             code = gs_setcolor(igs, &cc);
3990             return code;
3991         }
3992     }
3993     code = gs_cspace_new_DeviceN(&pcs, num_components, pacs, imemory);
3994     if (code < 0)
3995         return code;
3996     names = pcs->params.device_n.names;
3997     pmap = pcs->params.device_n.map;
3998     pcs->params.device_n.get_colorname_string = gs_get_colorname_string;
3999 
4000     /* Pick up the names of the components */
4001     {
4002         uint i;
4003         ref sname;
4004 
4005         for (i = 0; i < num_components; ++i) {
4006             array_get(imemory, &namesarray, (long)i, &sname);
4007             switch (r_type(&sname)) {
4008                 case t_string:
4009                     code = name_from_string(imemory, &sname, &sname);
4010                     if (code < 0) {
4011                         rc_decrement_cs(pcs, "setdevicenspace");
4012                         return code;
4013                     }
4014                     /* falls through */
4015                 case t_name:
4016                     names[i] = name_index(imemory, &sname);
4017                     break;
4018                 default:
4019                     rc_decrement_cs(pcs, "setdevicenspace");
4020                     return_error(e_typecheck);
4021             }
4022         }
4023     }
4024 
4025     /* Now set the current color space as DeviceN */
4026 
4027     cspace_old = istate->colorspace[0];
4028     istate->colorspace[0].procs.special.device_n.layer_names = namesarray;
4029     code = array_get(imemory, devicenspace, 3, &proc);
4030     if (code < 0)
4031         return code;
4032     istate->colorspace[0].procs.special.device_n.tint_transform = proc;
4033     gs_cspace_set_devn_function(pcs, pfn);
4034     code = gs_setcolorspace(igs, pcs);
4035     /* release reference from construction */
4036     rc_decrement_only_cs(pcs, "setdevicenspace");
4037     if (code < 0) {
4038         istate->colorspace[0] = cspace_old;
4039         return code;
4040     }
4041 
4042     cc.pattern = 0x00;
4043     for (i=0;i<num_components;i++)
4044         cc.paint.values[i] = 1.0;
4045     code = gs_setcolor(igs, &cc);
4046     *cont = 1;
4047     return code;
4048 }
validatedevicenspace(i_ctx_t * i_ctx_p,ref ** space)4049 static int validatedevicenspace(i_ctx_t * i_ctx_p, ref **space)
4050 {
4051     int i, code = 0;
4052     ref *devicenspace = *space, proc;
4053     ref nameref, sref, altspace, namesarray, sname;
4054 
4055     /* Check enough arguments in the space */
4056     if (r_size(devicenspace) < 4)
4057         return_error(e_rangecheck);
4058     /* Check the names parameter is an array */
4059     code = array_get(imemory, devicenspace, 1, &namesarray);
4060     if (code < 0)
4061         return code;
4062     if (!r_is_array(&namesarray))
4063         return_error(e_typecheck);
4064     /* Ensure we have at least one ink */
4065     if (r_size(&namesarray) < 1)
4066         return_error(e_typecheck);
4067     /* Make sure no more inks than we can cope with */
4068     if (r_size(&namesarray) > MAX_COMPONENTS_IN_DEVN)    /* MUST match psi/icremap.h int_remap_color_info_s */
4069         return_error(e_limitcheck);
4070     /* Check the tint transform is a procedure */
4071     code = array_get(imemory, devicenspace, 3, &proc);
4072     if (code < 0)
4073         return code;
4074     check_proc(proc);
4075 
4076     /* Check the array of ink names only contains names or strings */
4077     for (i = 0; i < r_size(&namesarray); ++i) {
4078         array_get(imemory, &namesarray, (long)i, &sname);
4079         switch (r_type(&sname)) {
4080                 case t_string:
4081                 case t_name:
4082                     break;
4083                 default:
4084                     return_error(e_typecheck);
4085         }
4086     }
4087 
4088     /* Get the name of the alternate space */
4089     code = array_get(imemory, devicenspace, 2, &altspace);
4090     if (code < 0)
4091         return code;
4092     if (r_has_type(&altspace, t_name))
4093         ref_assign(&nameref, &altspace);
4094     else {
4095         /* Make sure the alternate space is an array */
4096         if (!r_is_array(&altspace))
4097             return_error(e_typecheck);
4098         /* And has a name for its type */
4099         code = array_get(imemory, &altspace, 0, &nameref);
4100         if (code < 0)
4101             return code;
4102         if (!r_has_type(&nameref, t_name))
4103             return_error(e_typecheck);
4104     }
4105     /* Convert alternate space name to string */
4106     name_string_ref(imemory, &nameref, &sref);
4107     /* Check its not /Indexed, /Pattern, /DeviceN */
4108     if (r_size(&sref) == 7) {
4109         if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4110             return_error(e_typecheck);
4111         if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4112             return_error(e_typecheck);
4113         if (strncmp((const char *)sref.value.const_bytes, "DeviceN", 7) == 0)
4114             return_error(e_typecheck);
4115     }
4116     /* and also not /Separation */
4117     if (r_size(&sref) == 9 && strncmp((const char *)sref.value.const_bytes, "Separation", 9) == 0)
4118            return_error(e_typecheck);
4119 
4120     ref_assign(*space, &altspace);
4121     return 0;
4122 }
devicenalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4123 static int devicenalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4124 {
4125     ref altspace;
4126     int code;
4127 
4128     code = array_get(imemory, space, 2, &altspace);
4129     if (code < 0)
4130         return code;
4131     ref_assign(*r, &altspace);
4132     return 0;
4133 }
devicencomponents(i_ctx_t * i_ctx_p,ref * space,int * n)4134 static int devicencomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
4135 {
4136     ref namesarray;
4137     int code;
4138 
4139     code = array_get(imemory, space, 1, &namesarray);
4140     if (code < 0)
4141         return code;
4142     *n = r_size(&namesarray);
4143     return 0;
4144 }
devicendomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4145 static int devicendomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4146 {
4147     int i, limit, code;
4148     ref namesarray;
4149 
4150     code = array_get(imemory, space, 1, &namesarray);
4151     if (code < 0)
4152         return code;
4153 
4154     limit = r_size(&namesarray) * 2;
4155     for (i = 0;i < limit;i+=2) {
4156         ptr[i] = 0;
4157         ptr[i+1] = 1;
4158     }
4159     return 0;
4160 }
devicenrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4161 static int devicenrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4162 {
4163     int i, limit, code;
4164     PS_colour_space_t *cspace;
4165 
4166     ref altspace;
4167 
4168     code = array_get(imemory, space, 1, &altspace);
4169     if (code < 0)
4170         return code;
4171 
4172     code = get_space_object(i_ctx_p, &altspace, &cspace);
4173     if (code < 0)
4174         return code;
4175 
4176     code = cspace->numcomponents(i_ctx_p, &altspace, &limit);
4177     if (code < 0)
4178         return code;
4179 
4180     for (i = 0;i < limit * 2;i+=2) {
4181         ptr[i] = 0;
4182         ptr[i+1] = 1;
4183     }
4184     return 0;
4185 }
devicentransform(i_ctx_t * i_ctx_p,ref * devicenspace,int * usealternate,int * stage,int * stack_depth)4186 static int devicentransform(i_ctx_t *i_ctx_p, ref *devicenspace, int *usealternate, int *stage, int *stack_depth)
4187 {
4188     gx_device * dev = igs->device;
4189     ref narray, sname, proc;
4190     int i, code, colorant_number;
4191 
4192     *usealternate = 0;
4193     code = array_get(imemory, devicenspace, 1, &narray);
4194     if (code < 0)
4195         return code;
4196     if (!r_is_array(&narray))
4197         return_error(e_typecheck);
4198 
4199     for (i=0;i<r_size(&narray);i++) {
4200         code = array_get(imemory, &narray, i, &sname);
4201         if (code < 0)
4202             return code;
4203         if (r_has_type(&sname, t_name)) {
4204             name_string_ref(imemory, &sname, &sname);
4205         }
4206 
4207         /* Check for /All and /None, never need the alternate for these */
4208         if (r_size(&sname) == 3 &&
4209             strncmp("All", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4210             continue;
4211         if (r_size(&sname) == 4 &&
4212             strncmp("None", (const char *)sname.value.bytes, r_size(&sname)) == 0)
4213             continue;
4214         /*
4215          * Compare the colorant name to the device's.  If the device's
4216          * compare routine returns GX_DEVICE_COLOR_MAX_COMPONENTS then the
4217          * colorant is in the SeparationNames list but not in the
4218          * SeparationOrder list.
4219          */
4220         colorant_number = (*dev_proc(dev, get_color_comp_index))
4221                 (dev, (const char *)sname.value.bytes, r_size(&sname), SEPARATION_NAME);
4222         if (colorant_number < 0) {		/* If not valid colorant name */
4223             *usealternate = 1;
4224             break;
4225         }
4226     }
4227     if (*usealternate && *stage == 0) {
4228         (*stage)++;
4229         esp++;
4230         code = array_get(imemory, devicenspace, 3, &proc);
4231         if (code < 0)
4232             return code;
4233         *esp = proc;
4234         return o_push_estack;
4235     }
4236 
4237     if (*stage == 1){
4238         *stack_depth = 0;
4239         *stage = 0;
4240     }
4241     return 0;
4242 }
devicenbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4243 static int devicenbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4244 {
4245     os_ptr  op = osp;   /* required by "push" macro */
4246     int code, use, n_comp;
4247     ref narray;
4248 
4249     code = devicentransform(i_ctx_p, space, &use, stage, stack_depth);
4250     if (code !=  0)
4251         return code;
4252     if (!use) {
4253         *stage = 0;
4254         *cont = 0;
4255         code = array_get(imemory, space, 1, &narray);
4256         if (code < 0)
4257             return code;
4258         n_comp = r_size(&narray);
4259         pop(n_comp);
4260         op = osp;
4261         switch(base) {
4262         case 0:
4263             push(1);
4264             make_real(op, 0.0);
4265             break;
4266         case 1:
4267         case 2:
4268             push(3);
4269             make_real(&op[-2], 0.0);
4270             make_real(&op[-1], 0.0);
4271             make_real(op, 0.0);
4272             break;
4273         case 3:
4274             push(4);
4275             make_real(&op[-3], 0.0);
4276             make_real(&op[-2], 0.0);
4277             make_real(&op[-1], 0.0);
4278             make_real(op, 0.0);
4279             break;
4280         }
4281     } else {
4282         *stage = 0;
4283         *cont = 1;
4284     }
4285     return 0;
4286 }
devicenvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4287 static int devicenvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4288 {
4289     int i, code;
4290     ref narray;
4291     os_ptr op = osp;
4292 
4293     code = array_get(imemory, space, 1, &narray);
4294     if (code < 0)
4295         return code;
4296     if (!r_is_array(&narray))
4297         return_error(e_typecheck);
4298 
4299     if (num_comps < r_size(&narray))
4300         return_error(e_stackunderflow);
4301 
4302     op -= r_size(&narray) - 1;
4303 
4304     for (i=0;i < r_size(&narray); i++) {
4305         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4306             return_error(e_typecheck);
4307 
4308         if (values[i] > 1.0)
4309             values[i] = 1.0;
4310 
4311         if (values[i] < 0.0)
4312             values[i] = 0.0;
4313         op++;
4314     }
4315 
4316     return 0;
4317 }
devicencompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)4318 static int devicencompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
4319 {
4320     ref sname1, sname2;
4321     int code;
4322 
4323     code = array_get(imemory, space, 1, &sname1);
4324     if (code < 0)
4325         return 0;
4326 
4327     code = array_get(imemory, testspace, 1, &sname2);
4328     if (code < 0)
4329         return 0;
4330 
4331     if (!r_is_array(&sname1))
4332         return 0;
4333     if (!r_is_array(&sname2))
4334         return 0;
4335 
4336     if (!comparearrays(i_ctx_p, &sname1, &sname2))
4337         return 0;
4338 
4339     code = array_get(imemory, testspace, 2, &sname1);
4340     if (code < 0)
4341         return 0;
4342     code = array_get(imemory, testspace, 2, &sname2);
4343     if (code < 0)
4344         return 0;
4345     if (r_type(&sname1) != r_type(&sname2))
4346         return 0;
4347 
4348     if (r_is_array(&sname1)) {
4349         if (!comparearrays(i_ctx_p, &sname1, &sname2))
4350             return 0;
4351     } else {
4352         if (!r_has_type(&sname1, t_name))
4353             return 0;
4354         if (!name_eq(&sname1, &sname2))
4355             return 0;
4356     }
4357     code = array_get(imemory, space, 3, &sname1);
4358     if (code < 0)
4359         return 0;
4360     code = array_get(imemory, testspace, 3, &sname2);
4361     if (code < 0)
4362         return 0;
4363     return(comparearrays(i_ctx_p, &sname1, &sname2));
4364 }
deviceninitialproc(i_ctx_t * i_ctx_p,ref * space)4365 static int deviceninitialproc(i_ctx_t *i_ctx_p, ref *space)
4366 {
4367     gs_client_color cc;
4368     int i, num_components, code;
4369     ref namesarray;
4370 
4371     code = array_get(imemory, space, 1, &namesarray);
4372     if (code < 0)
4373         return code;
4374     num_components = r_size(&namesarray);
4375     cc.pattern = 0x00;
4376     for (i=0;i<num_components;i++)
4377         cc.paint.values[i] = 1.0;
4378     return gs_setcolor(igs, &cc);
4379 }
4380 
4381 /* Indexed */
4382 /*
4383  * This routine samples the indexed space, it pushes values from -1
4384  * to 'hival', then executes the tint transform procedure. Returns here
4385  * to store the resulting value(s) in the indexed map.
4386  */
4387 static int
indexed_cont(i_ctx_t * i_ctx_p)4388 indexed_cont(i_ctx_t *i_ctx_p)
4389 {
4390     os_ptr op = osp;
4391     es_ptr ep = esp;
4392     int i = (int)ep[csme_index].value.intval;
4393 
4394     if (i >= 0) {		/* i.e., not first time */
4395         int m = (int)ep[csme_num_components].value.intval;
4396         int code = float_params(op, m, &r_ptr(&ep[csme_map], gs_indexed_map)->values[i * m]);
4397 
4398         if (code < 0)
4399             return code;
4400         pop(m);
4401         op -= m;
4402         if (i == (int)ep[csme_hival].value.intval) {	/* All done. */
4403             esp -= num_csme;
4404             return o_pop_estack;
4405         }
4406     }
4407     push(1);
4408     ep[csme_index].value.intval = ++i;
4409     make_int(op, i);
4410     make_op_estack(ep + 1, indexed_cont);
4411     ep[2] = ep[csme_proc];	/* lookup proc */
4412     esp = ep + 2;
4413     return o_push_estack;
4414 }
setindexedspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4415 static int setindexedspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4416 {
4417     ref *pproc = &istate->colorspace[0].procs.special.index_proc;
4418     int code = 0;
4419     uint edepth = ref_stack_count(&e_stack);
4420     ref_colorspace cspace_old;
4421     ref hival, lookup;
4422     gs_color_space *pcs;
4423     gs_color_space *pcs_base;
4424 
4425     if (i_ctx_p->language_level < 2)
4426         return_error(e_undefined);
4427 
4428     *cont = 0;
4429     if (*stage == 1) {
4430         *stage = 0;
4431         return 0;
4432     }
4433 
4434     cspace_old = istate->colorspace[0];
4435 
4436     pcs_base = gs_currentcolorspace(igs);
4437 
4438     code = array_get(imemory, r, 3, &lookup);
4439     if (code < 0)
4440         return code;
4441     code = array_get(imemory, r, 2, &hival);
4442     if (code < 0)
4443         return code;
4444     if (r_has_type(&lookup, t_string)) {
4445         int num_values = (hival.value.intval + 1) * cs_num_components(pcs_base);
4446         byte *data_tmp;
4447 
4448         check_read(lookup);
4449         /*
4450          * The PDF and PS specifications state that the lookup table must have
4451          * the exact number of of data bytes needed.  However we have found
4452          * PDF files from Amyuni with extra data bytes.  Acrobat 6.0 accepts
4453          * these files without complaint, so we ignore the extra data.
4454          */
4455         if (r_size(&lookup) < num_values)
4456             return_error(e_rangecheck);
4457         pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4458         if (!pcs) {
4459             return_error(e_VMerror);
4460         }
4461         pcs->base_space = pcs_base;
4462         rc_increment_cs(pcs_base);
4463 
4464         data_tmp = (byte *) (pcs->params.indexed.lookup.table.data = ialloc_string (lookup.tas.rsize, "setindexedspace"));
4465         if (!data_tmp) {
4466             rc_decrement(pcs, "setindexedspace");
4467             return_error(e_VMerror);
4468         }
4469 
4470         memcpy(data_tmp, lookup.value.const_bytes, lookup.tas.rsize);
4471 
4472         pcs->params.indexed.lookup.table.size = num_values;
4473         pcs->params.indexed.use_proc = 0;
4474         make_null(pproc);
4475         code = 0;
4476     } else {
4477         gs_indexed_map *map;
4478 
4479         /*
4480          * We have to call zcs_begin_map before moving the parameters,
4481          * since if the color space is a DeviceN or Separation space,
4482          * the memmove will overwrite its parameters.
4483          */
4484         code = zcs_begin_map(i_ctx_p, &map, &lookup, (hival.value.intval + 1),
4485                              pcs_base, indexed_cont);
4486         if (code < 0)
4487             return code;
4488         pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Indexed);
4489         pcs->base_space = pcs_base;
4490         rc_increment_cs(pcs_base);
4491         pcs->params.indexed.use_proc = 1;
4492         *pproc = lookup;
4493         map->proc.lookup_index = lookup_indexed_map;
4494         pcs->params.indexed.lookup.map = map;
4495     }
4496     pcs->params.indexed.hival = hival.value.intval;
4497     pcs->params.indexed.n_comps = cs_num_components(pcs_base);
4498     code = gs_setcolorspace(igs, pcs);
4499     /* release reference from construction */
4500     rc_decrement_only_cs(pcs, "setindexedspace");
4501     if (code < 0) {
4502         istate->colorspace[0] = cspace_old;
4503         ref_stack_pop_to(&e_stack, edepth);
4504         return code;
4505     }
4506     *stage = 0;
4507     if (ref_stack_count(&e_stack) == edepth) {
4508         return 0;
4509     } else {
4510         *cont = 1;
4511         *stage = 1;
4512         return o_push_estack; /* installation will load the caches */
4513     }
4514 }
validateindexedspace(i_ctx_t * i_ctx_p,ref ** space)4515 static int validateindexedspace(i_ctx_t * i_ctx_p, ref **space)
4516 {
4517     int code = 0;
4518     ref *r = *space;
4519     ref nameref, sref, hival, lookup, altspace;
4520 
4521     if (!r_is_array(r))
4522         return_error(e_typecheck);
4523     /* Validate parameters, check we have enough operands */
4524     if (r_size(r) != 4)
4525         return_error(e_rangecheck);
4526     /* Check operand type(s) */
4527     /* Make sure 'hival' is an integer */
4528     code = array_get(imemory, r, 2, &hival);
4529     if (code < 0)
4530         return code;
4531     if (!r_has_type(&hival, t_integer))
4532         return_error(e_typecheck);
4533     /* Make sure 'hival' lies between 0 and 4096 */
4534     if (hival.value.intval < 0 || hival.value.intval > 4096)
4535         return_error(e_rangecheck);
4536     /* Ensure the 'lookup' is either a string or a procedure */
4537     code = array_get(imemory, r, 3, &lookup);
4538     if (code < 0)
4539         return code;
4540     if (!r_has_type(&lookup, t_string))
4541         check_proc(lookup);
4542 
4543     /* Get the name of the alternate space */
4544     code = array_get(imemory, r, 1, &altspace);
4545     if (code < 0)
4546         return code;
4547     if (r_has_type(&altspace, t_name))
4548         ref_assign(&nameref, &altspace);
4549     else {
4550         if (!r_is_array(&altspace))
4551             return_error(e_typecheck);
4552         code = array_get(imemory, &altspace, 0, &nameref);
4553         if (code < 0)
4554             return code;
4555     }
4556     /* Convert alternate space name to string */
4557     name_string_ref(imemory, &nameref, &sref);
4558     /* Check its not /Indexed or /Pattern */
4559     if (r_size(&sref) == 7) {
4560         if (strncmp((const char *)sref.value.const_bytes, "Indexed", 7) == 0)
4561             return_error(e_typecheck);
4562         if (strncmp((const char *)sref.value.const_bytes, "Pattern", 7) == 0)
4563             return_error(e_typecheck);
4564     }
4565     ref_assign(*space, &altspace);
4566     return 0;
4567 }
indexedalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4568 static int indexedalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4569 {
4570     ref alt;
4571     int code;
4572 
4573     code = array_get(imemory, *r, 1, &alt);
4574     if (code < 0)
4575         return code;
4576     ref_assign(*r, &alt);
4577     return 0;
4578 }
indexeddomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4579 static int indexeddomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4580 {
4581     ref hival;
4582     int code;
4583 
4584     code = array_get(imemory, space, 2, &hival);
4585     if (code < 0)
4586         return code;
4587     ptr[0] = 0;
4588     ptr[1] = (float)hival.value.intval;
4589     return 0;
4590 }
indexedrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4591 static int indexedrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4592 {
4593     ref hival;
4594     int code;
4595 
4596     code = array_get(imemory, space, 2, &hival);
4597     if (code < 0)
4598         return code;
4599     ptr[0] = 0;
4600     ptr[1] = (float)hival.value.intval;
4601     return 0;
4602 }
indexedbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4603 static int indexedbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4604 {
4605     int code;
4606 
4607     if (*stage == 0) {
4608         /* Usefully /Indexed can't be the base of any other space, so we know
4609          * the current space in the graphics state is this one.
4610          */
4611         gs_color_space *pcs;
4612         pcs = gs_currentcolorspace(igs);
4613 
4614         /* Update the counters */
4615         *stage = 1;
4616         *cont = 1;
4617 
4618         /* Indexed spaces can have *either* a procedure or a string for the
4619          * lookup.
4620          */
4621         if (pcs->params.indexed.use_proc) {
4622             es_ptr ep = ++esp;
4623             ref proc;
4624 
4625             /* We have a procedure, set up the continuation to run the
4626              * lookup procedure. (The index is already on the operand stack)
4627              */
4628             check_estack(1);
4629             code = array_get(imemory, space, 3, &proc);
4630             if (code < 0)
4631                 return code;
4632             *ep = proc;	/* lookup proc */
4633             return o_push_estack;
4634         } else {
4635             int i, index;
4636             os_ptr op = osp;
4637             unsigned char *ptr = (unsigned char *)pcs->params.indexed.lookup.table.data;
4638 
4639             *stage = 0;
4640             /* We have a string, start by retrieving the index from the op stack */
4641             /* Make sure its an integer! */
4642             if (!r_has_type(op, t_integer))
4643                 return_error (e_typecheck);
4644             index = op->value.intval;
4645             /* And remove it from the stack. */
4646             pop(1);
4647             op = osp;
4648 
4649             /* Make sure we have enough space on the op stack to hold
4650              * one value for each component of the alternate space
4651              */
4652             push(pcs->params.indexed.n_comps);
4653             op -= pcs->params.indexed.n_comps - 1;
4654 
4655             /* Move along the lookup table, one byte for each component , the
4656              * number of times required to get to the lookup for this index
4657              */
4658             ptr += index * pcs->params.indexed.n_comps;
4659 
4660             /* For all the components of the alternate space, push the value
4661              * of the component on the stack. The value is given by the byte
4662              * from the lookup table divided by 255 to give a value between
4663              * 0 and 1.
4664              */
4665             for (i = 0; i < pcs->params.indexed.n_comps; i++, op++) {
4666                 float rval = (*ptr++) / 255.0;
4667                 make_real(op, rval);
4668             }
4669             return 0;
4670         }
4671     } else {
4672         *stage = 0;
4673         *cont = 1;
4674         return 0;
4675     }
4676 }
indexedvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4677 static int indexedvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4678 {
4679     int code;
4680     ref hival;
4681     os_ptr op = osp;
4682 
4683     if (num_comps < 1)
4684         return_error(e_stackunderflow);
4685 
4686     if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
4687         return_error(e_typecheck);
4688 
4689     code = array_get(imemory, space, 2, &hival);
4690     if (code < 0)
4691         return code;
4692 
4693     if (*values > hival.value.intval)
4694         *values = (float)hival.value.intval;
4695 
4696     if (*values < 0)
4697         *values = 0;
4698 
4699     /* The PLRM says 'If it is a real number, it is rounded to the nearest integer
4700      * but in fact Acrobat simply floors the value.
4701      */
4702     *values = floor(*values);
4703 
4704     return 0;
4705 }
4706 
4707 /* Pattern */
setpatternspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4708 static int setpatternspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4709 {
4710     gs_color_space *pcs;
4711     gs_color_space *pcs_base;
4712     uint edepth = ref_stack_count(&e_stack);
4713     int code = 0;
4714 
4715     if (i_ctx_p->language_level < 2)
4716         return_error(e_undefined);
4717 
4718     *cont = 0;
4719     pcs_base = NULL;
4720     if (r_is_array(r)) {
4721         check_read(*r);
4722 
4723         switch (r_size(r)) {
4724             case 1:		/* no base space */
4725                 pcs_base = NULL;
4726                 break;
4727             default:
4728                 return_error(e_rangecheck);
4729             case 2:
4730                 pcs_base = gs_currentcolorspace(igs);
4731                 if (cs_num_components(pcs_base) < 0)       /* i.e., Pattern space */
4732                     return_error(e_rangecheck);
4733         }
4734     }
4735     pcs = gs_cspace_alloc(imemory, &gs_color_space_type_Pattern);
4736     pcs->base_space = pcs_base;
4737     pcs->params.pattern.has_base_space = (pcs_base != NULL);
4738     rc_increment_cs(pcs_base);
4739     code = gs_setcolorspace(igs, pcs);
4740     /* release reference from construction */
4741     rc_decrement_only_cs(pcs, "zsetpatternspace");
4742     if (code < 0) {
4743         ref_stack_pop_to(&e_stack, edepth);
4744         return code;
4745     }
4746     make_null(&istate->pattern[0]); /* PLRM: initial color value is a null object */
4747     *stage = 0;
4748     return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);	/* installation will load the caches */
4749 }
validatepatternspace(i_ctx_t * i_ctx_p,ref ** r)4750 static int validatepatternspace(i_ctx_t * i_ctx_p, ref **r)
4751 {
4752     int code;
4753     ref tref;
4754 
4755     /* since makepattern has already been run, we don't need to do much validation */
4756     if (!r_has_type(*r, t_name)) {
4757         if (r_is_array(*r)) {
4758             if (r_size(*r) > 1) {
4759                 code = array_get(imemory, *r, 1, &tref);
4760                 if (code < 0)
4761                     return code;
4762                 ref_assign(*r, &tref);
4763             } else
4764                 *r = 0;
4765         } else
4766             return_error(e_typecheck);
4767     } else
4768         *r = 0;
4769     return 0;
4770 }
patternalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)4771 static int patternalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
4772 {
4773     ref tref;
4774     int code;
4775 
4776     if (!r_has_type(*r, t_name)) {
4777         if (r_is_array(*r)) {
4778             if (r_size(*r) > 1) {
4779                 code = array_get(imemory, space, 1, &tref);
4780                 if (code < 0)
4781                     return code;
4782                 ref_assign(*r, &tref);
4783             } else
4784                 *r = 0;
4785         } else
4786             return_error(e_typecheck);
4787     } else
4788         *r = 0;
4789     return 0;
4790 }
patterncomponent(i_ctx_t * i_ctx_p,ref * space,int * n)4791 static int patterncomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
4792 {
4793     os_ptr op = osp;
4794     int n_comps, code;
4795     const gs_color_space *  pcs = gs_currentcolorspace(igs);
4796     gs_client_color         cc;
4797 
4798     /* check for a pattern color space */
4799     if ((n_comps = cs_num_components(pcs)) < 0) {
4800         n_comps = -n_comps;
4801         if (r_has_type(op, t_dictionary)) {
4802             ref     *pImpl, pPatInst;
4803 
4804             code = dict_find_string(op, "Implementation", &pImpl);
4805             if (code < 0)
4806                 return code;
4807             code = array_get(imemory, pImpl, 0, &pPatInst);
4808             if (code < 0)
4809                 return code;
4810             cc.pattern = r_ptr(&pPatInst, gs_pattern_instance_t);
4811             if (pattern_instance_uses_base_space(cc.pattern))
4812                 *n = n_comps;
4813             else
4814                 *n = 1;
4815         } else
4816             *n = 1;
4817     } else
4818         return_error(e_typecheck);
4819 
4820     return 0;
4821 }
patternbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4822 static int patternbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4823 {
4824     os_ptr op;
4825     int i, components=0;
4826 
4827     if (r_size(space) > 1) {
4828         const gs_color_space *  pcs = gs_currentcolorspace(igs);
4829         const gs_client_color * pcc = gs_currentcolor(igs);
4830         int                     n = cs_num_components(pcs);
4831         bool                    push_pattern = n < 0;
4832         gs_pattern_instance_t * pinst = pcc->pattern;
4833 
4834         if (pinst != 0 && pattern_instance_uses_base_space(pinst)) {
4835             /* check for pattern */
4836             if (push_pattern)
4837                 pop(1);	    /* The pattern instance */
4838             *stage = 0;
4839             *cont = 1;
4840             return 0;
4841         }
4842         /* If the pattern isn't yet initialised, or doesn't use the
4843          * base space, treat as uncolored and return defaults below
4844          * Fall Through.
4845          */
4846     }
4847 
4848     pop(1);
4849     op = osp;
4850     switch(base) {
4851         case 0:
4852             components = 1;
4853             break;
4854         case 1:
4855         case 2:
4856             components = 3;
4857             break;
4858         case 3:
4859             components = 4;
4860             break;
4861     }
4862     push(components);
4863     op -= components-1;
4864     for (i=0;i<components;i++) {
4865         make_real(op, (float)0);
4866         op++;
4867     }
4868     if (components == 4) {
4869         op--;
4870         make_real(op, (float)1);
4871     }
4872     *stage = 0;
4873     *cont = 0;
4874     return 0;
4875 }
patternvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4876 static int patternvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4877 {
4878     os_ptr op = osp;
4879 
4880     check_op(1);
4881 
4882     if (!r_has_type(op, t_dictionary) && !r_has_type(op, t_null))
4883         return_error(e_typecheck);
4884 
4885     return 0;
4886 }
4887 
4888 /* DevicePixel */
setdevicepspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)4889 static int setdevicepspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
4890 {
4891     int code = 0;
4892     gs_color_space *pcs;
4893     ref bpp;
4894 
4895     /* The comment in the original PostScript (gs_lev2.ps) said
4896      * "DevicePixel is actually a LanguageLevel 3 feature; it is here for
4897      *  historical reasons." Actually DevicePixel is a Display PostScript
4898      * space, as far as I can tell. It certainly isn't a level 3 space.
4899      * Preserve the old behaviour anyway.
4900      */
4901     if (i_ctx_p->language_level < 2)
4902         return_error(e_undefined);
4903 
4904     *cont = 0;
4905     code = array_get(imemory, r, 1, &bpp);
4906     if (code < 0)
4907         return code;
4908     if (!r_has_type(&bpp, t_integer))
4909         return_error(e_typecheck);
4910     code = gs_cspace_new_DevicePixel(imemory, &pcs, (int)bpp.value.intval);
4911     if (code < 0)
4912         return code;
4913     code = gs_setcolorspace(igs, pcs);
4914     /* release reference from construction */
4915     *stage = 0;
4916     rc_decrement_only_cs(pcs, "setseparationspace");
4917     return code;
4918 }
validatedevicepspace(i_ctx_t * i_ctx_p,ref ** space)4919 static int validatedevicepspace(i_ctx_t * i_ctx_p, ref **space)
4920 {
4921     int code = 0;
4922     ref *r = *space, bpp;
4923 
4924     if (!r_is_array(r))
4925         return_error(e_typecheck);
4926     /* Validate parameters, check we have enough operands */
4927     if (r_size(r) != 2)
4928         return_error(e_rangecheck);
4929     /* Make sure 'bits per pixel' is an integer */
4930     code = array_get(imemory, r, 1, &bpp);
4931     if (code < 0)
4932         return code;
4933     if (!r_has_type(&bpp, t_integer))
4934         return_error(e_typecheck);
4935 
4936     /* Make sure 'bits per pixel' lies between 0 and 31 */
4937     if (bpp.value.intval < 0 || bpp.value.intval > 31)
4938         return_error(e_rangecheck);
4939 
4940     *space = 0;
4941     return code;
4942 }
devicepdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)4943 static int devicepdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4944 {
4945     int code;
4946     ref tref;
4947 
4948     code = array_get(imemory, space, 1, &tref);
4949     if (code < 0)
4950         return code;
4951     ptr[0] = 0;
4952     ptr[1] = (float)(1 << tref.value.intval);
4953     return 0;
4954 }
deviceprange(i_ctx_t * i_ctx_p,ref * space,float * ptr)4955 static int deviceprange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
4956 {
4957     int code;
4958     ref tref;
4959 
4960     code = array_get(imemory, space, 1, &tref);
4961     if (code < 0)
4962         return code;
4963     ptr[0] = 0;
4964     ptr[1] = (float)(1 << tref.value.intval);
4965     return 0;
4966 }
devicepbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)4967 static int devicepbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
4968 {
4969     os_ptr  op = osp;
4970 
4971     *stage = 0;
4972     *cont = 0;
4973     make_int(op, 0);
4974     return 0;
4975 }
devicepvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)4976 static int devicepvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
4977 {
4978     return 0;
4979 }
4980 
set_dev_space(i_ctx_t * i_ctx_p,int components)4981 static int set_dev_space(i_ctx_t * i_ctx_p, int components)
4982 {
4983     int code, stage = 1, cont = 0;
4984     switch(components) {
4985         case 1:
4986             code = setgrayspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4987             break;
4988         case 3:
4989             code = setrgbspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4990             break;
4991         case 4:
4992             code = setcmykspace(i_ctx_p, (ref *)0, &stage, &cont, 1);
4993             break;
4994         default:
4995             code = gs_note_error(e_rangecheck);
4996             break;
4997     }
4998     return code;
4999 }
5000 
5001 /* Lab Space */
5002 
5003 /* Check that the range of a the ab values is valid */
checkrangeab(i_ctx_t * i_ctx_p,ref * labdict)5004 static int checkrangeab(i_ctx_t * i_ctx_p, ref *labdict)
5005 {
5006     int code = 0, i;
5007     float value[4];
5008     ref *tempref, valref;
5009 
5010     code = dict_find_string(labdict, "Range", &tempref);
5011     if (code >= 0 && !r_has_type(tempref, t_null)) {
5012         if (!r_is_array(tempref))
5013             return_error(e_typecheck);
5014         if (r_size(tempref) != 4)
5015             return_error(e_rangecheck);
5016 
5017         for (i=0;i<4;i++) {
5018             code = array_get(imemory, tempref, i, &valref);
5019             if (code < 0)
5020                 return code;
5021             if (r_has_type(&valref, t_integer))
5022                 value[i] = (float)valref.value.intval;
5023             else if (r_has_type(&valref, t_real))
5024                 value[i] = (float)valref.value.realval;
5025             else
5026                 return_error(e_typecheck);
5027         }
5028         if (value[1] < value[0] || value[3] < value[2] )
5029             return_error(e_rangecheck);
5030     }
5031     return 0;
5032 }
5033 
setlabspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5034 static int setlabspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont,
5035                        int CIESubst)
5036 {
5037     /* In this case, we will treat this as an ICC color space, with a
5038        CIELAB 16 bit profile */
5039     ref labdict;
5040     int code = 0;
5041     float                   range_buff[4], white[3], black[3];
5042     static const float      dflt_range[4] = { -100, 100, -100, 100 };
5043     static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5044     int i;
5045     gs_client_color cc;
5046 
5047     *cont = 0;
5048     code = array_get(imemory, r, 1, &labdict);
5049     if (code < 0)
5050         return code;
5051 /* Get all the parts */
5052     code = dict_floats_param( imemory, &labdict, "Range", 4, range_buff,
5053                               dflt_range );
5054     for (i = 0; i < 4 && range_buff[i + 1] >= range_buff[i]; i += 2);
5055     if (i != 4)
5056         return_error(e_rangecheck);
5057     code = dict_floats_param( imemory, &labdict, "BlackPoint", 3, black,
5058                               dflt_black );
5059      code = dict_floats_param( imemory, &labdict, "WhitePoint", 3, white,
5060                               dflt_white );
5061      if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5062         return_error(e_rangecheck);
5063     code = seticc_lab(i_ctx_p, white, black, range_buff);
5064     if ( code < 0)
5065         return gs_rethrow(code, "setting PDF lab color space");
5066     cc.pattern = 0x00;
5067     for (i=0;i<3;i++)
5068         cc.paint.values[i] = 0;
5069     code = gs_setcolor(igs, &cc);
5070     return code;
5071 }
5072 
validatelabspace(i_ctx_t * i_ctx_p,ref ** r)5073 static int validatelabspace(i_ctx_t * i_ctx_p, ref **r)
5074 {
5075     int code=0;
5076     ref *space, labdict;
5077 
5078     space = *r;
5079     if (!r_is_array(space))
5080         return_error(e_typecheck);
5081     /* Validate parameters, check we have enough operands */
5082     if (r_size(space) < 2)
5083         return_error(e_rangecheck);
5084     code = array_get(imemory, space, 1, &labdict);
5085     if (code < 0)
5086         return code;
5087     /* Check the white point, which is required. */
5088     code = checkWhitePoint(i_ctx_p, &labdict);
5089     if (code != 0)
5090         return code;
5091     /* The rest are optional.  Need to validate though */
5092     code = checkBlackPoint(i_ctx_p, &labdict);
5093     if (code < 0)
5094         return code;
5095     /* Range on a b values */
5096     code = checkrangeab(i_ctx_p, &labdict);
5097     if (code < 0)
5098         return code;
5099     *r = 0;  /* No nested space */
5100     return 0;
5101 }
5102 
labrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5103 static int labrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5104 {
5105     int i, code;
5106     ref     CIEdict, *tempref, valref;
5107 
5108     code = array_get(imemory, space, 1, &CIEdict);
5109     if (code < 0)
5110         return code;
5111 
5112     /* If we have a Range entry, get the values from that */
5113     code = dict_find_string(&CIEdict, "Range", &tempref);
5114     if (code >= 0 && !r_has_type(tempref, t_null)) {
5115         for (i=0;i<4;i++) {
5116             code = array_get(imemory, tempref, i, &valref);
5117             if (code < 0)
5118                 return code;
5119             if (r_has_type(&valref, t_integer))
5120                 ptr[i] = (float)valref.value.intval;
5121             else if (r_has_type(&valref, t_real))
5122                 ptr[i] = (float)valref.value.realval;
5123             else
5124                 return_error(e_typecheck);
5125         }
5126     } else {
5127         /* Default values for Lab */
5128         for (i=0;i<2;i++) {
5129             ptr[2 * i] = -100;
5130             ptr[(2 * i) + 1] = 100;
5131         }
5132     }
5133     return 0;
5134 }
5135 
labdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5136 static int labdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5137 {
5138     int i, code;
5139     ref     CIEdict, *tempref, valref;
5140 
5141     code = array_get(imemory, space, 1, &CIEdict);
5142     if (code < 0)
5143         return code;
5144 
5145     /* If we have a Range, get the values from that */
5146     code = dict_find_string(&CIEdict, "Range", &tempref);
5147     if (code >= 0 && !r_has_type(tempref, t_null)) {
5148         for (i=0;i<4;i++) {
5149             code = array_get(imemory, tempref, i, &valref);
5150             if (code < 0)
5151                 return code;
5152             if (r_has_type(&valref, t_integer))
5153                 ptr[i] = (float)valref.value.intval;
5154             else if (r_has_type(&valref, t_real))
5155                 ptr[i] = (float)valref.value.realval;
5156             else
5157                 return_error(e_typecheck);
5158         }
5159     } else {
5160         /* Default values for Lab */
5161         for (i=0;i<2;i++) {
5162             ptr[2 * i] = -100;
5163             ptr[(2 * i) + 1] = 100;
5164         }
5165     }
5166     return 0;
5167 }
5168 
labbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)5169 static int labbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5170 {
5171     os_ptr op;
5172     int i, components=1;
5173 
5174     components = 3;
5175     pop(components);
5176     op = osp;
5177     components = 3;
5178     push(components);
5179     op -= components-1;
5180     for (i=0;i<components;i++) {
5181         make_real(op, (float)0);
5182         op++;
5183     }
5184     *stage = 0;
5185     *cont = 0;
5186     return 0;
5187 }
5188 
labvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)5189 static int labvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5190 {
5191     os_ptr op = osp;
5192     int i;
5193 
5194     if (num_comps < 3)
5195         return_error(e_stackunderflow);
5196     op -= 2;
5197     for (i=0;i<3;i++) {
5198         if (!r_has_type(op, t_integer) && !r_has_type(op, t_real))
5199             return_error(e_typecheck);
5200         op++;
5201     }
5202     return 0;
5203 }
5204 
5205 /* Check that the Matrix of a CalRGB and CalGray space is valid */
checkCalMatrix(i_ctx_t * i_ctx_p,ref * CIEdict)5206 static int checkCalMatrix(i_ctx_t * i_ctx_p, ref *CIEdict)
5207 {
5208     int code = 0, i;
5209     float value[9];
5210     ref *tempref, valref;
5211 
5212     code = dict_find_string(CIEdict, "Matrix", &tempref);
5213     if (code >= 0 && !r_has_type(tempref, t_null)) {
5214         if (!r_is_array(tempref))
5215             return_error(e_typecheck);
5216         if (r_size(tempref) != 9)
5217             return_error(e_rangecheck);
5218         for (i=0;i<9;i++) {
5219             code = array_get(imemory, tempref, i, &valref);
5220             if (code < 0)
5221                 return code;
5222             if (r_has_type(&valref, t_integer))
5223                 value[i] = (float)valref.value.intval;
5224             else if (r_has_type(&valref, t_real))
5225                 value[i] = (float)valref.value.realval;
5226             else
5227                 return_error(e_typecheck);
5228         }
5229     }
5230     return 0;
5231 }
5232 
5233 /* Check that the Gamma of a CalRGB and CalGray space is valid */
checkGamma(i_ctx_t * i_ctx_p,ref * CIEdict,int numvalues)5234 static int checkGamma(i_ctx_t * i_ctx_p, ref *CIEdict, int numvalues)
5235 {
5236     int code = 0, i;
5237     float value[3];
5238     ref *tempref, valref;
5239 
5240     code = dict_find_string(CIEdict, "Gamma", &tempref);
5241     if (code >= 0 && !r_has_type(tempref, t_null)) {
5242         if (numvalues > 1) {
5243             /* Array of gammas (RGB) */
5244             if (!r_is_array(tempref))
5245                 return_error(e_typecheck);
5246             if (r_size(tempref) != numvalues)
5247                 return_error(e_rangecheck);
5248             for (i=0;i<numvalues;i++) {
5249                 code = array_get(imemory, tempref, i, &valref);
5250                 if (code < 0)
5251                     return code;
5252                 if (r_has_type(&valref, t_integer))
5253                     value[i] = (float)valref.value.intval;
5254                 else if (r_has_type(&valref, t_real))
5255                     value[i] = (float)valref.value.realval;
5256                 else
5257                     return_error(e_typecheck);
5258                 if (value[i] <= 0) return_error(e_rangecheck);
5259             }
5260         } else {
5261             /* Single gamma (gray) */
5262             if (r_has_type(tempref, t_real))
5263                 value[0] = (float)(tempref->value.realval);
5264             else if (r_has_type(tempref, t_integer))
5265                     value[0] = (float)(tempref->value.intval);
5266             else
5267                 return_error(e_typecheck);
5268             if (value[0] <= 0) return_error(e_rangecheck);
5269         }
5270     }
5271     return 0;
5272 }
5273 
5274 /* Here we set up an equivalent ICC form for the CalGray color space */
setcalgrayspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5275 static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5276 {
5277     ref graydict;
5278     int code = 0;
5279     float                   gamma, white[3], black[3];
5280     floatp                  dflt_gamma = 1.0;
5281     static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5282     gs_client_color cc;
5283 
5284     *cont = 0;
5285     code = array_get(imemory, r, 1, &graydict);
5286     if (code < 0)
5287         return code;
5288 /* Get all the parts */
5289     code = dict_float_param(&graydict, "Gamma",
5290                  dflt_gamma, &gamma);
5291     if (gamma <= 0 ) return_error(e_rangecheck);
5292      code = dict_floats_param( imemory,
5293                               &graydict,
5294                               "BlackPoint",
5295                               3,
5296                               black,
5297                               dflt_black );
5298      code = dict_floats_param( imemory,
5299                               &graydict,
5300                               "WhitePoint",
5301                               3,
5302                               white,
5303                               dflt_white );
5304      if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5305         return_error(e_rangecheck);
5306     code = seticc_cal(i_ctx_p, white, black, &gamma, NULL, 1,
5307                         graydict.value.saveid);
5308     if ( code < 0)
5309         return gs_rethrow(code, "setting CalGray  color space");
5310     cc.pattern = 0x00;
5311     cc.paint.values[0] = 0;
5312     code = gs_setcolor(igs, &cc);
5313     return code;
5314 }
5315 
validatecalgrayspace(i_ctx_t * i_ctx_p,ref ** r)5316 static int validatecalgrayspace(i_ctx_t * i_ctx_p, ref **r)
5317 {
5318     int code=0;
5319     ref *space, calgraydict;
5320 
5321     space = *r;
5322     if (!r_is_array(space))
5323         return_error(e_typecheck);
5324     /* Validate parameters, check we have enough operands */
5325     if (r_size(space) < 2)
5326         return_error(e_rangecheck);
5327     code = array_get(imemory, space, 1, &calgraydict);
5328     if (code < 0)
5329         return code;
5330     /* Check the white point, which is required */
5331     /* We have to have a white point */
5332     /* Check white point exists, and is an array of three numbers */
5333     code = checkWhitePoint(i_ctx_p, &calgraydict);
5334     if (code != 0)
5335         return code;
5336     /* The rest are optional.  Need to validate though */
5337     code = checkBlackPoint(i_ctx_p, &calgraydict);
5338     if (code < 0)
5339         return code;
5340     /* Check Gamma values */
5341     code = checkGamma(i_ctx_p, &calgraydict, 1);
5342     if (code < 0)
5343         return code;
5344     *r = 0;  /* No nested space */
5345     return 0;
5346 }
5347 
5348 /* Here we set up an equivalent ICC form for the CalRGB color space */
setcalrgbspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5349 static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5350 {
5351     ref rgbdict;
5352     int code = 0;
5353     float                   gamma[3], white[3], black[3], matrix[9];
5354     static const float      dflt_gamma[3] = { 1.0, 1.0, 1.0 };
5355     static const float      dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
5356     static const float      dflt_matrix[9] = {1,0,0,0,1,0,0,0,1};
5357     int i;
5358     gs_client_color cc;
5359 
5360     *cont = 0;
5361     code = array_get(imemory, r, 1, &rgbdict);
5362     if (code < 0)
5363         return code;
5364 /* Get all the parts */
5365     code = dict_floats_param( imemory,
5366                               &rgbdict,
5367                               "Gamma",
5368                               3,
5369                               gamma,
5370                               dflt_gamma );
5371      if (gamma[0] <= 0 || gamma[1] <= 0 || gamma[2] <= 0)
5372         return_error(e_rangecheck);
5373      code = dict_floats_param( imemory,
5374                               &rgbdict,
5375                               "BlackPoint",
5376                               3,
5377                               black,
5378                               dflt_black );
5379      code = dict_floats_param( imemory,
5380                               &rgbdict,
5381                               "WhitePoint",
5382                               3,
5383                               white,
5384                               dflt_white );
5385      if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
5386         return_error(e_rangecheck);
5387      code = dict_floats_param( imemory,
5388                               &rgbdict,
5389                               "Matrix",
5390                               9,
5391                               matrix,
5392                               dflt_matrix );
5393     code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, rgbdict.value.saveid);
5394     if ( code < 0)
5395         return gs_rethrow(code, "setting CalRGB  color space");
5396     cc.pattern = 0x00;
5397     for (i=0;i<3;i++)
5398         cc.paint.values[i] = 0;
5399     code = gs_setcolor(igs, &cc);
5400     return code;
5401 }
5402 
validatecalrgbspace(i_ctx_t * i_ctx_p,ref ** r)5403 static int validatecalrgbspace(i_ctx_t * i_ctx_p, ref **r)
5404 {
5405     int code=0;
5406     ref *space, calrgbdict;
5407 
5408     space = *r;
5409     if (!r_is_array(space))
5410         return_error(e_typecheck);
5411     /* Validate parameters, check we have enough operands */
5412     if (r_size(space) < 2)
5413         return_error(e_rangecheck);
5414     code = array_get(imemory, space, 1, &calrgbdict);
5415     if (code < 0)
5416         return code;
5417     /* Check the white point, which is required */
5418     code = checkWhitePoint(i_ctx_p, &calrgbdict);
5419     if (code != 0)
5420         return code;
5421     /* The rest are optional.  Need to validate though */
5422     code = checkBlackPoint(i_ctx_p, &calrgbdict);
5423     if (code < 0)
5424         return code;
5425     /* Check Gamma values */
5426     code = checkGamma(i_ctx_p, &calrgbdict, 3);
5427     if (code < 0)
5428         return code;
5429     /* Check Matrix */
5430     code = checkCalMatrix(i_ctx_p, &calrgbdict);
5431     if (code < 0)
5432         return code;
5433     *r = 0;  /* No nested space */
5434     return 0;
5435 }
5436 
5437 /* ICCBased */
5438 static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr);
seticcspace(i_ctx_t * i_ctx_p,ref * r,int * stage,int * cont,int CIESubst)5439 static int seticcspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
5440 {
5441     os_ptr op = osp;
5442     ref     ICCdict, *tempref, *altref=NULL, *nocie;
5443     int components, code;
5444     float range[8];
5445 
5446     code = dict_find_string(systemdict, "NOCIE", &nocie);
5447     if (code < 0)
5448         return code;
5449     if (!r_has_type(nocie, t_boolean))
5450         return_error(e_typecheck);
5451     *cont = 0;
5452     do {
5453         switch(*stage) {
5454             case 0:
5455                 (*stage)++;
5456                 code = array_get(imemory, r, 1, &ICCdict);
5457                 if (code < 0)
5458                     return code;
5459                 code = dict_find_string(&ICCdict, "N", &tempref);
5460                 if (code < 0)
5461                     return code;
5462                 components = tempref->value.intval;
5463                 if (components > count_of(range))
5464                     return_error(e_rangecheck);
5465 
5466                 /* Don't allow ICCBased spaces if NOCIE is true */
5467                 if (nocie->value.boolval) {
5468                     code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5469                     if (code < 0)
5470                         return code;
5471                     if ((altref != NULL) && (r_type(altref) != t_null)) {
5472                         /* The PDF interpreter sets a null Alternate. If we have an
5473                          * Alternate, and its not null, and NOCIE is true, then use the
5474                          * Alternate instead of the ICC
5475                          */
5476                         push(1);
5477                         ref_assign(op, altref);
5478                         /* If CIESubst, we are already substituting for CIE, so use nosubst
5479                          * to prevent further substitution!
5480                          */
5481                         return setcolorspace_nosubst(i_ctx_p);
5482                     } else {
5483                         /* There's no /Alternate (or it is null), set a default space
5484                          * based on the number of components in the ICCBased space
5485                          */
5486                         code = set_dev_space(i_ctx_p, components);
5487                         if (code != 0)
5488                             return code;
5489                         *stage = 0;
5490                     }
5491                 } else {
5492                     code = iccrange(i_ctx_p, r, (float *)&range);
5493                     if (code < 0)
5494                         return code;
5495                     code = dict_find_string(&ICCdict, "DataSource", &tempref);
5496                     if (code < 0)
5497                         return code;
5498                     /* Check for string based ICC and convert to a file */
5499                     if (r_has_type(tempref, t_string)){
5500                         uint n = r_size(tempref);
5501                         ref rss;
5502 
5503                         code = make_rss(i_ctx_p, &rss, tempref->value.const_bytes, n, r_space(tempref), 0L, n, false);
5504                         if (code < 0)
5505                             return code;
5506                         ref_assign(tempref, &rss);
5507                     }
5508                     /* Make space on operand stack to pass the ICC dictionary */
5509                     push(1);
5510                     ref_assign(op, &ICCdict);
5511                     code = seticc(i_ctx_p, components, op, (float *)&range);
5512                     if (code < 0) {
5513                         code = dict_find_string(&ICCdict, "Alternate", &altref); /* Alternate is optional */
5514                         if (code < 0)
5515                             return code;
5516                         if ((altref != NULL) && (r_type(altref) != t_null)) {
5517                             /* We have a /Alternate in the ICC space */
5518                             /* Our ICC dictionary still on operand stack, we can reuse the
5519                              * slot on the stack to hold the alternate space.
5520                              */
5521                             ref_assign(op, (ref *)altref);
5522                             /* If CIESubst, we are already substituting for CIE, so use nosubst
5523                              * to prevent further substitution!
5524                              */
5525                             if (CIESubst)
5526                                 return setcolorspace_nosubst(i_ctx_p);
5527                             else
5528                                 return zsetcolorspace(i_ctx_p);
5529                         } else {
5530                             /* We have no /Alternate in the ICC space, use hte /N key to
5531                              * determine an 'appropriate' default space.
5532                              */
5533                             code = set_dev_space(i_ctx_p, components);
5534                             if (code != 0)
5535                                 return code;
5536                             *stage = 0;
5537                         }
5538                         pop(1);
5539                     }
5540                     if (code != 0)
5541                         return code;
5542                 }
5543                 break;
5544             case 1:
5545                 /* All done, exit */
5546                 *stage = 0;
5547                 code = 0;
5548                 break;
5549             default:
5550                 return_error (e_rangecheck);
5551                 break;
5552         }
5553     }while(*stage);
5554     return code;
5555 }
validateiccspace(i_ctx_t * i_ctx_p,ref ** r)5556 static int validateiccspace(i_ctx_t * i_ctx_p, ref **r)
5557 {
5558     int code=0, i, components = 0;
5559     ref *space, *tempref, valref, ICCdict, sref;
5560 
5561     space = *r;
5562     if (!r_is_array(space))
5563         return_error(e_typecheck);
5564     /* Validate parameters, check we have enough operands */
5565     if (r_size(space) != 2)
5566         return_error(e_rangecheck);
5567 
5568     code = array_get(imemory, space, 1, &ICCdict);
5569     if (code < 0)
5570         return code;
5571 
5572     code = dict_find_string(&ICCdict, "N", &tempref);
5573     if (code <= 0)
5574         return code;
5575     if (!r_has_type(tempref, t_null)) {
5576         if (!r_has_type(tempref, t_integer))
5577             return_error(e_typecheck);
5578         components = tempref->value.intval;
5579     } else
5580         return_error(e_typecheck);
5581     code = dict_find_string(&ICCdict, "DataSource", &tempref);
5582     if (code <= 0)
5583         return_error(e_typecheck);
5584     if (!r_has_type(tempref, t_null)) {
5585         if (!r_has_type(tempref, t_string) && !r_has_type(tempref, t_file))
5586             return_error(e_typecheck);
5587     } else
5588         return_error(e_typecheck);
5589 
5590     /* Following are optional entries */
5591     code = dict_find_string(&ICCdict, "Range", &tempref);
5592     if (code >= 0 && !r_has_type(tempref, t_null)) {
5593         if (!r_is_array(tempref))
5594             return_error(e_typecheck);
5595         if (r_size(tempref) < (components * 2))
5596             return_error(e_rangecheck);
5597         for (i=0;i<components * 2;i++) {
5598             code = array_get(imemory, tempref, i, &valref);
5599             if (code < 0)
5600                 return code;
5601             if (!r_has_type(&valref, t_integer) && !r_has_type(&valref, t_real))
5602                 return_error(e_typecheck);
5603         }
5604     }
5605     code = dict_find_string(&ICCdict, "Alternate", &tempref);
5606     if (code >= 0 && !r_has_type(tempref, t_null)) {
5607         ref_assign(*r, tempref);
5608         if (r_has_type(tempref, t_name)) {
5609             name_string_ref(imemory, tempref, &sref);
5610             if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5611                 return_error(e_typecheck);
5612         } else {
5613             if (r_is_array(tempref)) {
5614                 code = array_get(imemory, tempref, 0, &valref);
5615                 if (code < 0)
5616                     return code;
5617                 if (!r_has_type(&valref, t_name) && !r_has_type(&valref, t_string))
5618                     return_error(e_typecheck);
5619                 if (r_has_type(&valref, t_name))
5620                     name_string_ref(imemory, &valref, &sref);
5621                 else
5622                     sref.value.bytes = valref.value.bytes;
5623                 if (sref.value.bytes && strncmp((const char *)sref.value.bytes, "Pattern", 7) == 0)
5624                     return_error(e_typecheck);
5625             } else
5626                 return_error(e_typecheck);
5627         }
5628     } else {
5629         ref nameref;
5630 
5631         switch (components) {
5632             case 1:
5633                 code = name_enter_string(imemory, "DeviceGray", &nameref);
5634                 break;
5635             case 3:
5636                 code = name_enter_string(imemory, "DeviceRGB", &nameref);
5637                 break;
5638             case 4:
5639                 code = name_enter_string(imemory, "DeviceCMYK", &nameref);
5640                 break;
5641             default:
5642                 return_error(e_rangecheck);
5643         }
5644         /* In case this space is the /ALternate for a previous ICCBased space
5645          * insert the named space into the ICC dictionary. If we simply returned
5646          * the named space, as before, then we are replacing the second ICCBased
5647          * space in the first ICCBased space with the named space!
5648          */
5649         code = idict_put_string(&ICCdict, "Alternate", &nameref);
5650         if (code < 0)
5651             return code;
5652 
5653         /* And now revalidate with the newly updated dictionary */
5654         return validateiccspace(i_ctx_p, r);
5655     }
5656     return code;
5657 }
5658 
iccalternatespace(i_ctx_t * i_ctx_p,ref * space,ref ** r,int * CIESubst)5659 static int iccalternatespace(i_ctx_t * i_ctx_p, ref *space, ref **r, int *CIESubst)
5660 {
5661     int components, code = 0;
5662     ref *tempref, ICCdict;
5663 
5664     if (!r_is_array(space))
5665         return_error(e_typecheck);
5666     /* Validate parameters, check we have enough operands */
5667     if (r_size(space) != 2)
5668         return_error(e_rangecheck);
5669 
5670     code = array_get(imemory, space, 1, &ICCdict);
5671     if (code < 0)
5672         return code;
5673 
5674     code = dict_find_string(&ICCdict, "N", &tempref);
5675     if (code <= 0)
5676         return code;
5677 
5678     components = tempref->value.intval;
5679 
5680     code = dict_find_string(&ICCdict, "Alternate", &tempref);
5681     if (code >= 0 && !r_has_type(tempref, t_null)) {
5682         *r = tempref;
5683     } else {
5684         switch (components) {
5685             case 1:
5686                 code = name_enter_string(imemory, "DeviceGray", *r);
5687                 break;
5688             case 3:
5689                 code = name_enter_string(imemory, "DeviceRGB", *r);
5690                 break;
5691             case 4:
5692                 code = name_enter_string(imemory, "DeviceCMYK", *r);
5693                 break;
5694             default:
5695                 return_error(e_rangecheck);
5696         }
5697     }
5698     *CIESubst = 1;
5699     return code;
5700 }
icccomponents(i_ctx_t * i_ctx_p,ref * space,int * n)5701 static int icccomponents(i_ctx_t * i_ctx_p, ref *space, int *n)
5702 {
5703     int code = 0;
5704     ref *tempref, ICCdict;
5705 
5706     code = array_get(imemory, space, 1, &ICCdict);
5707     if (code < 0)
5708         return code;
5709 
5710     code = dict_find_string(&ICCdict, "N", &tempref);
5711     *n = tempref->value.intval;
5712     return 0;
5713 }
iccdomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5714 static int iccdomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5715 {
5716     int components, i, code = 0;
5717     ref *tempref, ICCdict, valref;
5718 
5719     code = array_get(imemory, space, 1, &ICCdict);
5720     if (code < 0)
5721         return code;
5722     code = dict_find_string(&ICCdict, "N", &tempref);
5723     components = tempref->value.intval;
5724     code = dict_find_string(&ICCdict, "Range", &tempref);
5725     if (code >= 0 && !r_has_type(tempref, t_null)) {
5726         for (i=0;i<components * 2;i++) {
5727             code = array_get(imemory, tempref, i, &valref);
5728             if (code < 0)
5729                 return code;
5730             if (r_has_type(&valref, t_integer))
5731                 ptr[i * 2] = (float)valref.value.intval;
5732             else
5733                 ptr[i * 2] = valref.value.realval;
5734         }
5735     } else {
5736         for (i=0;i<components;i++) {
5737             ptr[i * 2] = 0;
5738             ptr[(i * 2) + 1] = 1;
5739         }
5740     }
5741     return 0;
5742 }
iccrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5743 static int iccrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5744 {
5745     int components, i, code = 0;
5746     ref *tempref, ICCdict, valref;
5747 
5748     code = array_get(imemory, space, 1, &ICCdict);
5749     if (code < 0)
5750         return code;
5751     code = dict_find_string(&ICCdict, "N", &tempref);
5752     components = tempref->value.intval;
5753     code = dict_find_string(&ICCdict, "Range", &tempref);
5754     if (code >= 0 && !r_has_type(tempref, t_null)) {
5755         for (i=0;i<components * 2;i++) {
5756             code = array_get(imemory, tempref, i, &valref);
5757             if (code < 0)
5758                 return code;
5759             if (r_has_type(&valref, t_integer))
5760                 ptr[i] = (float)valref.value.intval;
5761             else
5762                 ptr[i] = (float)valref.value.realval;
5763         }
5764     } else {
5765         for (i=0;i<components;i++) {
5766             ptr[i * 2] = 0;
5767             ptr[(i * 2) + 1] = 1;
5768         }
5769     }
5770     return 0;
5771 }
iccbasecolor(i_ctx_t * i_ctx_p,ref * space,int base,int * stage,int * cont,int * stack_depth)5772 static int iccbasecolor(i_ctx_t * i_ctx_p, ref *space, int base, int *stage, int *cont, int *stack_depth)
5773 {
5774     *stage = 0;
5775     *cont = 1;
5776     return 0;
5777 }
iccvalidate(i_ctx_t * i_ctx_p,ref * space,float * values,int num_comps)5778 static int iccvalidate(i_ctx_t *i_ctx_p, ref *space, float *values, int num_comps)
5779 {
5780     return 0;
5781 }
5782 
dummydomain(i_ctx_t * i_ctx_p,ref * space,float * ptr)5783 static int dummydomain(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5784 {
5785     return 0;
5786 }
dummyrange(i_ctx_t * i_ctx_p,ref * space,float * ptr)5787 static int dummyrange(i_ctx_t * i_ctx_p, ref *space, float *ptr)
5788 {
5789     return 0;
5790 }
onecomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5791 static int onecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5792 {
5793     *n = 1;
5794     return 0;
5795 }
threecomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5796 static int threecomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5797 {
5798     *n = 3;
5799     return 0;
5800 }
fourcomponent(i_ctx_t * i_ctx_p,ref * space,int * n)5801 static int fourcomponent(i_ctx_t * i_ctx_p, ref *space, int *n)
5802 {
5803     *n = 4;
5804     return 0;
5805 }
truecompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)5806 static int truecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5807 {
5808     return 1;
5809 }
falsecompareproc(i_ctx_t * i_ctx_p,ref * space,ref * testspace)5810 static int falsecompareproc(i_ctx_t *i_ctx_p, ref *space, ref *testspace)
5811 {
5812     return 0;
5813 }
5814 
5815 PS_colour_space_t colorProcs[] = {
5816     {(char *)"DeviceGray", setgrayspace, 0, 0, onecomponent, grayrange, graydomain,
5817     graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5818     {(char *)"DeviceRGB", setrgbspace, 0, 0, threecomponent, rgbrange, rgbdomain,
5819     rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc},
5820     {(char *)"DeviceCMYK", setcmykspace, 0, 0, fourcomponent, cmykrange, cmykdomain,
5821     cmykbasecolor, 0, cmykvalidate, truecompareproc, cmykinitialproc},
5822     {(char *)"CIEBasedA", setcieaspace, validatecieaspace, 0, onecomponent, ciearange, cieadomain,
5823     ciebasecolor, 0, cieavalidate, cieacompareproc, 0},
5824     {(char *)"CIEBasedABC", setcieabcspace, validatecieabcspace, 0, threecomponent, cieabcrange, cieabcdomain,
5825     ciebasecolor, 0, cieabcvalidate, cieabccompareproc, 0},
5826     {(char *)"CIEBasedDEF", setciedefspace, validateciedefspace, 0, threecomponent, ciedefrange, ciedefdomain,
5827     ciebasecolor, 0, ciedefvalidate, ciedefcompareproc, 0},
5828     {(char *)"CIEBasedDEFG", setciedefgspace, validateciedefgspace, 0, fourcomponent, ciedefgrange, ciedefgdomain,
5829     ciebasecolor, 0, ciedefgvalidate, ciedefgcompareproc, 0},
5830     {(char *)"Separation", setseparationspace, validateseparationspace, separationalternatespace, onecomponent, seprange, sepdomain,
5831     sepbasecolor, septransform, sepvalidate, sepcompareproc, sepinitialproc},
5832     {(char *)"DeviceN", setdevicenspace, validatedevicenspace, devicenalternatespace, devicencomponents, devicenrange, devicendomain,
5833     devicenbasecolor, devicentransform, devicenvalidate, devicencompareproc, deviceninitialproc},
5834     {(char *)"Indexed", setindexedspace, validateindexedspace, indexedalternatespace, onecomponent, indexedrange, indexeddomain,
5835     indexedbasecolor, 0, indexedvalidate, falsecompareproc, 0},
5836     {(char *)"Pattern", setpatternspace, validatepatternspace, patternalternatespace, patterncomponent, dummyrange, dummydomain,
5837     patternbasecolor, 0, patternvalidate, falsecompareproc, 0},
5838     {(char *)"DevicePixel", setdevicepspace, validatedevicepspace, 0, onecomponent, deviceprange, devicepdomain,
5839     devicepbasecolor, 0, devicepvalidate, falsecompareproc, 0},
5840     {(char *)"ICCBased", seticcspace, validateiccspace, iccalternatespace, icccomponents, iccrange, iccdomain,
5841     iccbasecolor, 0, iccvalidate, falsecompareproc, 0},
5842     {(char *)"Lab", setlabspace, validatelabspace, 0, threecomponent, labrange, labdomain,
5843     labbasecolor, 0, labvalidate, truecompareproc, 0},
5844     {(char *)"CalGray", setcalgrayspace, validatecalgrayspace, 0, onecomponent, grayrange, graydomain,
5845     graybasecolor, 0, grayvalidate, truecompareproc, grayinitialproc},
5846     {(char *)"CalRGB", setcalrgbspace, validatecalrgbspace, 0, threecomponent, rgbrange, rgbdomain,
5847     rgbbasecolor, 0, rgbvalidate, truecompareproc, rgbinitialproc}
5848 };
5849 
5850 /*
5851  * Given a color space, this finds the appropriate object from the list above
5852  */
get_space_object(i_ctx_t * i_ctx_p,ref * arr,PS_colour_space_t ** obj)5853 int get_space_object(i_ctx_t *i_ctx_p, ref *arr, PS_colour_space_t **obj)
5854 {
5855     ref spacename, nref;
5856     int i, nprocs = sizeof(colorProcs) / sizeof(PS_colour_space_t), code;
5857 
5858     /* If the spaece is an array, the first element is always the name */
5859     if (r_is_array(arr))
5860         code = array_get(imemory, arr, 0, &spacename);
5861     else
5862         ref_assign(&spacename, arr);
5863 
5864     /* Check that it really is a name */
5865     if (!r_has_type(&spacename, t_name))
5866         return_error(e_typecheck);
5867 
5868     /* Find the relevant color space object */
5869     for (i=0;i<nprocs;i++) {
5870         code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)colorProcs[i].name, strlen(colorProcs[i].name), &nref, 0);
5871         if (code < 0)
5872             return code;
5873         if (name_eq(&spacename, &nref)) {
5874             *obj = &colorProcs[i];
5875             return 0;
5876         }
5877     }
5878     return_error(e_undefined);
5879 }
5880 /*
5881  * This routine checks all the color spaces in an operand by
5882  * calling the specific 'validate' method for each in turn. It also
5883  * returns the 'depth' which is the number of nested spaces.
5884  */
validate_spaces(i_ctx_t * i_ctx_p,ref * arr,int * depth)5885 static int validate_spaces(i_ctx_t *i_ctx_p, ref *arr, int *depth)
5886 {
5887     ref space, *sp = &space;
5888     int code = 0;
5889     PS_colour_space_t *obj;
5890 
5891     ref_assign(&space, arr);
5892     *depth = 0;
5893     do {
5894         code = get_space_object(i_ctx_p, sp, &obj);
5895         if (code < 0)
5896             return code;
5897 
5898         (*depth)++;
5899         if (!obj->validateproc)
5900             break;
5901 
5902         code = obj->validateproc(i_ctx_p, &sp);
5903         if (code < 0)
5904             return code;
5905     }while(sp);
5906     return 0;
5907 }
5908 /*
5909  * The routine which does all the setcolor dispatching. This is initially set up by
5910  * zsetcolor above. Because setcolorspace samples the space and converts the tint
5911  * transform to a function, we don't need to run the PS tint transform in order to
5912  * set the color. However, some applications, notably Photoshop 5 and above, rely
5913  * on the tint transform being executed, so we must do so if the normal PostScript
5914  * processing would result in the tintr transform being executed.
5915  *
5916  *  We check each space in turn to see whether we would normally run the tint
5917  * transform, eg Indexed is always executed, Separation and DeviceN only if the
5918  * required ink(s) aren't present in the device. If we discover that any space
5919  * doesn't require a tint transform, then we can short-circuit the processing.
5920  * Otherwise we set up to execute the tint transform.
5921  */
5922 static int
setcolor_cont(i_ctx_t * i_ctx_p)5923 setcolor_cont(i_ctx_t *i_ctx_p)
5924 {
5925     ref arr, *parr = &arr;
5926     es_ptr ep = esp;
5927     int i=0, code = 0,depth, usealternate, stage, stack_depth, CIESubst = 0;
5928     PS_colour_space_t *obj;
5929 
5930     stack_depth = (int)ep[-3].value.intval;
5931     depth = (int)ep[-2].value.intval;
5932     stage = (int)ep[-1].value.intval;
5933     /* If we get a continuation from a sub-procedure, we will want to come back
5934      * here afterward, to do any remaining spaces. We need to set up for that now.
5935      * so that our continuation is ahead of the sub-proc's continuation.
5936      */
5937     check_estack(1);
5938     push_op_estack(setcolor_cont);
5939 
5940     while (code == 0) {
5941         ref_assign(&arr, ep);
5942         /* Run along the nested color spaces until we get to the first one
5943          * that we haven't yet processed (given by 'depth')
5944          */
5945         for (i=0;i<=depth;i++) {
5946             code = get_space_object(i_ctx_p, parr, &obj);
5947             if (code < 0)
5948                 return code;
5949 
5950             if (i < (depth)) {
5951                 if (!obj->alternateproc) {
5952                     return_error(e_typecheck);
5953                 }
5954                 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
5955                 if (code < 0)
5956                     return code;
5957             }
5958         }
5959         if (obj->runtransformproc) {
5960             code = obj->runtransformproc(i_ctx_p, &istate->colorspace[0].array, &usealternate, &stage, &stack_depth);
5961             make_int(&ep[-3], stack_depth);
5962             make_int(&ep[-1], stage);
5963             if (code != 0) {
5964                 return code;
5965             }
5966             make_int(&ep[-2], ++depth);
5967             if (!usealternate)
5968                 break;
5969         } else
5970             break;
5971     }
5972     /* Remove our next continuation and our data */
5973     obj->numcomponents(i_ctx_p, parr, &i);
5974     pop(i);
5975     esp -= 5;
5976     return o_pop_estack;
5977 }
5978 /*
5979  * The routine which does all the setcolorspace dispatching. This is initially set up by
5980  * zsetcolorspace above. It starts by descending to the bottom-most space
5981  * and setting that as the current space. It then descends the array again
5982  * to the next-to-bottom- space and sets that as the current, and so on.
5983  *
5984  * The 'stage' parameter is passed in to each 'set' method. If a method needs
5985  * to do a continuation itself (eg sample a space) then it should set the stage
5986  * to a non-zero value. When the continuation is complete we return here, and
5987  * attempt to 'set' the same space again. This time stage will be whatever was
5988  * set the first time, which is a signal to the 'set' routine that a continuation
5989  * took place, and is complete. Stage must always be set to 0 when a 'set'
5990  * of a color space is complete.
5991  */
5992 static int
setcolorspace_cont(i_ctx_t * i_ctx_p)5993 setcolorspace_cont(i_ctx_t *i_ctx_p)
5994 {
5995     ref arr, *parr = &arr;
5996     os_ptr op = osp;
5997     es_ptr ep = esp, pdepth, pstage, pCIESubst;
5998     int i, code = 0,depth, stage, cont, CIESubst = 0;
5999     PS_colour_space_t *obj;
6000 
6001     pCIESubst = &ep[-3];
6002     pdepth = &ep[-2];
6003     pstage = &ep[-1];
6004 
6005     CIESubst = (int)pCIESubst->value.intval;
6006     depth = (int)pdepth->value.intval;
6007     stage = (int)pstage->value.intval;
6008     /* If we get a continuation from a sub-procedure, we will want to come back
6009      * here afterward, to do any remaining stages. We need to set up for that now.
6010      * so that our continuation is ahead of the sub-proc's continuation.
6011      */
6012     check_estack(1);
6013     push_op_estack(setcolorspace_cont);
6014 
6015     while (code == 0 && depth) {
6016         ref_assign(&arr, ep);
6017         /* Run along the nested color spaces until we get to the lowest one
6018          * that we haven't yet processed (given by 'depth')
6019          */
6020         for (i = 0;i < depth;i++) {
6021             code = get_space_object(i_ctx_p, parr, &obj);
6022             if (code < 0)
6023                 return code;
6024 
6025             if (i < (depth - 1)) {
6026                 if (!obj->alternateproc) {
6027                     return_error(e_typecheck);
6028                 }
6029                 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6030                 if (code < 0)
6031                     return code;
6032             }
6033         }
6034 
6035         code = obj->setproc(i_ctx_p, parr, &stage, &cont, CIESubst);
6036         make_int(pstage, stage);
6037         if (code != 0)
6038             return code;
6039         if (!cont) {
6040             /* Completed that space, decrement the 'depth' */
6041             make_int(pdepth, --depth);
6042             parr = &arr;
6043         }
6044     }
6045     if (code == 0) {
6046         /* Remove our next continuation and our data */
6047         esp -= 5;
6048         op = osp;
6049         istate->colorspace[0].array = *op;
6050         /* Remove the colorspace array form the operand stack */
6051         pop(1);
6052         code = o_pop_estack;
6053     }
6054     return code;
6055 }
6056 /*
6057  * The routine which does all the dispatching for the device-space specific
6058  * operators below (eg setgray). This is initially set up by the routines below.
6059  *
6060  * It would seem unnecessary to have a continuation procedure, because at first
6061  * sight these can only be a single space with no alternate and can't require
6062  * sampling, because they are device space. However if UseCIEColor is true, then
6063  * we will actually use a Default Color Space Array in place of the requested color
6064  * space. These are often CIEBased spaces, and these do need to be sampled. So
6065  * actually we do need a continuation procedure, unfortunately.
6066  *
6067  * Also, we need to set the initial color value after we have set the color space.
6068  */
6069 static int
setdevicecolor_cont(i_ctx_t * i_ctx_p)6070 setdevicecolor_cont(i_ctx_t *i_ctx_p)
6071 {
6072     os_ptr op = osp;
6073     es_ptr ep = esp, pstage;
6074     int code = 0, stage, base;
6075 
6076     pstage = ep;
6077     base = (int)ep[-1].value.intval;
6078     stage = (int)pstage->value.intval;
6079     /* If we get a continuation from a sub-procedure, we will want to come back
6080      * here afterward, to do any remaining stages. We need to set up for that now.
6081      * so that our continuation is ahead of the sub-proc's continuation.
6082      */
6083     check_estack(1);
6084     /* May need to push a /Device... name on the stack so make sure we have space */
6085     check_ostack(1);
6086     /* The push_op_estack macro increments esp before use, so we don't need to */
6087     push_op_estack(setdevicecolor_cont);
6088 
6089     do {
6090         switch(stage) {
6091             case 0:
6092                 make_int(pstage, ++stage);
6093                 push(1);
6094                 switch(base) {
6095                     case 0: /* DeviceGray */
6096                         code = name_enter_string(imemory, "DeviceGray", op);
6097                         break;
6098                     case 1: /* DeviceRGB */
6099                         code = name_enter_string(imemory, "DeviceRGB", op);
6100                         break;
6101                     case 2: /* DeviceCMYK */
6102                         code = name_enter_string(imemory, "DeviceCMYK", op);
6103                         break;
6104                 }
6105                 if (code < 0)
6106                     return code;
6107                 code = zsetcolorspace(i_ctx_p);
6108                 if (code != 0)
6109                     return code;
6110                 break;
6111             case 1:
6112                 make_int(pstage, ++stage);
6113                 code = zsetcolor(i_ctx_p);
6114                 if (code != 0)
6115                     return code;
6116                 break;
6117             case 2:
6118                 esp -= 3;
6119                 return o_pop_estack;
6120                 break;
6121         }
6122     }while(1);
6123     return 0;
6124 }
6125 
6126 /* These routines implement the device-space set color routines
6127  * These set both the space and the color in a single operation.
6128  * Previously these were implemented in PostScript.
6129  */
6130 static int
zsetgray(i_ctx_t * i_ctx_p)6131 zsetgray(i_ctx_t * i_ctx_p)
6132 {
6133     os_ptr  op = osp;   /* required by "push" macro */
6134     float value;
6135     int code;
6136 
6137     /* Gather numeric operand value(s) */
6138     code = float_params(op, 1, &value);
6139     if (code < 0)
6140         return code;
6141     /* Clamp numeric operand range(s) */
6142     if (value < 0)
6143         value = 0;
6144     else if (value > 1)
6145         value = 1;
6146     code = make_floats(op, &value, 1);
6147     if (code < 0)
6148         return code;
6149 
6150     /* Set up for the continuation procedure which will do the work */
6151     /* Make sure the exec stack has enough space */
6152     check_estack(5);
6153     push_mark_estack(es_other, colour_cleanup);
6154     esp++;
6155     /* variable to hold base type (0 = gray) */
6156     make_int(esp, 0);
6157     esp++;
6158     /* Store the 'stage' of processing (initially 0) */
6159     make_int(esp, 0);
6160     /* Finally, the actual continuation routine */
6161     push_op_estack(setdevicecolor_cont);
6162     return o_push_estack;
6163 }
6164 static int
zsethsbcolor(i_ctx_t * i_ctx_p)6165 zsethsbcolor(i_ctx_t * i_ctx_p)
6166 {
6167     os_ptr  op = osp;   /* required by "push" macro */
6168     int code, i;
6169     float values[3];
6170 
6171     /* Gather numeric operand value(s) (also checks type) */
6172     code = float_params(op, 3, (float *)&values);
6173     if (code < 0)
6174         return code;
6175     /* Clamp numeric operand range(s) */
6176     for (i = 0;i < 3; i++) {
6177         if (values[i] < 0)
6178             values[i] = 0;
6179         else if (values[i] > 1)
6180             values[i] = 1;
6181     }
6182 
6183     hsb2rgb((float *)&values);
6184 
6185     code = make_floats(&op[-2], (const float *)&values, 3);
6186     if (code < 0)
6187         return code;
6188 
6189     /* Set up for the continuation procedure which will do the work */
6190     /* Make sure the exec stack has enough space */
6191     check_estack(5);
6192     push_mark_estack(es_other, colour_cleanup);
6193     esp++;
6194     /* variable to hold base type (1 = RGB) */
6195     make_int(esp, 1);
6196     esp++;
6197     /* Store the 'stage' of processing (initially 0) */
6198     make_int(esp, 0);
6199     /* Finally, the actual continuation routine */
6200     push_op_estack(setdevicecolor_cont);
6201     return o_push_estack;
6202 }
6203 static int
zsetrgbcolor(i_ctx_t * i_ctx_p)6204 zsetrgbcolor(i_ctx_t * i_ctx_p)
6205 {
6206     os_ptr  op = osp;   /* required by "push" macro */
6207     int code, i;
6208     float values[3];
6209 
6210     /* Gather numeric operand value(s) (also checks type) */
6211     code = float_params(op, 3, (float *)&values);
6212     if (code < 0)
6213         return code;
6214     /* Clamp numeric operand range(s) */
6215     for (i = 0;i < 3; i++) {
6216         if (values[i] < 0)
6217             values[i] = 0;
6218         else if (values[i] > 1)
6219             values[i] = 1;
6220     }
6221 
6222     code = make_floats(&op[-2], (const float *)&values, 3);
6223     if (code < 0)
6224         return code;
6225 
6226     /* Set up for the continuation procedure which will do the work */
6227     /* Make sure the exec stack has enough space */
6228     check_estack(5);
6229     push_mark_estack(es_other, colour_cleanup);
6230     esp++;
6231     /* variable to hold base type (1 = RGB) */
6232     make_int(esp, 1);
6233     esp++;
6234     /* Store the 'stage' of processing (initially 0) */
6235     make_int(esp, 0);
6236     /* Finally, the actual continuation routine */
6237     push_op_estack(setdevicecolor_cont);
6238     return o_push_estack;
6239 }
6240 
6241 static int
zsetcmykcolor(i_ctx_t * i_ctx_p)6242 zsetcmykcolor(i_ctx_t * i_ctx_p)
6243 {
6244     os_ptr  op = osp;   /* required by "push" macro */
6245     int code, i;
6246     float values[4];
6247 
6248     /* Gather numeric operand value(s) (also checks type) */
6249     code = float_params(op, 4, (float *)&values);
6250     if (code < 0)
6251         return code;
6252     /* Clamp numeric operand range(s) */
6253     for (i = 0;i < 4; i++) {
6254         if (values[i] < 0)
6255             values[i] = 0;
6256         else if (values[i] > 1)
6257             values[i] = 1;
6258     }
6259 
6260     code = make_floats(&op[-3], (const float *)&values, 4);
6261     if (code < 0)
6262         return code;
6263 
6264     /* Set up for the continuation procedure which will do the work */
6265     /* Make sure the exec stack has enough space */
6266     check_estack(5);
6267     push_mark_estack(es_other, colour_cleanup);
6268     esp++;
6269     /* variable to hold base type (2 = CMYK) */
6270     make_int(esp, 2);
6271     esp++;
6272     /* Store the 'stage' of processing (initially 0) */
6273     make_int(esp, 0);
6274     /* Finally, the actual continuation routine */
6275     push_op_estack(setdevicecolor_cont);
6276     return o_push_estack;
6277 }
6278 
6279 /*
6280  * The routine which does all the dispatching for the device-space specific
6281  * 'current color' routines currentgray, currentrgbcolo and currentcmykcolor.
6282  *
6283  * Starting with the top-level color space we need to take the current color
6284  * value(s) and pass it through the tint transform procedure (actually we use the
6285  * converted function) to get equivalent components for the next space. We then
6286  * repeat with each alternate space in turn until we reach a 'terminal' space.
6287  * That can be a device space (eg DeviceGray), a CIEBased or ICCBased space, or
6288  * a Separation or DeviceN space which is not using its alternate space.
6289  *
6290  * Depending on which kind of terminal space we reach we will either return
6291  * fixed values (all 0.0) or we will convert the terminal device space components
6292  * into the requested device space.
6293  *
6294  * Because we might need to run a tint transform procedure, this requires a
6295  * continuation procedure.
6296  */
6297 static int
currentbasecolor_cont(i_ctx_t * i_ctx_p)6298 currentbasecolor_cont(i_ctx_t *i_ctx_p)
6299 {
6300     ref arr, *parr = &arr;
6301     es_ptr ep = esp;
6302     int i, code = 0,depth, stage, base, cont=1, stack_depth = 0, CIESubst=0;
6303     PS_colour_space_t *obj;
6304 
6305     stack_depth = (int)ep[-4].value.intval;
6306     base = (int)ep[-3].value.intval;
6307     depth = (int)ep[-2].value.intval;
6308     stage = (int)ep[-1].value.intval;
6309     /* If we get a continuation from a sub-procedure, we will want to come back
6310      * here afterward, to do any remaining stages. We need to set up for that now.
6311      * so that our continuation is ahead of the sub-proc's continuation.
6312      */
6313     check_estack(1);
6314     /* The push_op_estack macro increments esp before use, so we don't need to */
6315     push_op_estack(currentbasecolor_cont);
6316 
6317     while (code == 0 && cont) {
6318         ref_assign(&arr, ep);
6319         parr = &arr;
6320         /* Run along the nested color spaces until we get to the lowest one
6321          * that we haven't yet processed (given by 'depth')
6322          */
6323         for (i = 0;i < depth;i++) {
6324             code = get_space_object(i_ctx_p, parr, &obj);
6325             if (code < 0)
6326                 return code;
6327 
6328             if (i < (depth - 1)) {
6329                 if (!obj->alternateproc) {
6330                     return_error(e_typecheck);
6331                 }
6332                 code = obj->alternateproc(i_ctx_p, parr, &parr, &CIESubst);
6333                 if (code < 0)
6334                     return code;
6335             }
6336         }
6337 
6338         code = obj->basecolorproc(i_ctx_p, parr, base, &stage, &cont, &stack_depth);
6339         make_int(&ep[-4], stack_depth);
6340         make_int(&ep[-1], stage);
6341         if (code != 0)
6342             return code;
6343         /* Completed that space, increment the 'depth' */
6344         make_int(&ep[-2], ++depth);
6345     }
6346     if (code == 0) {
6347         /* Remove our next continuation and our data */
6348         esp -= 7;
6349         code = o_pop_estack;
6350     }
6351     return code;
6352 }
6353 
6354 /* These routines implement the device-space 'current' color routines.
6355  * Previously these were implemented in PostScript.
6356  */
6357 static int
zcurrentgray(i_ctx_t * i_ctx_p)6358 zcurrentgray(i_ctx_t * i_ctx_p)
6359 {
6360     int code, depth;
6361 
6362     code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6363     if (code < 0)
6364         return code;
6365 
6366     code = zcurrentcolor(i_ctx_p);
6367     if (code < 0)
6368         return code;
6369     /* Set up for the continuation procedure which will do the work */
6370     /* Make sure the exec stack has enough space */
6371     check_estack(7);
6372     push_mark_estack(es_other, colour_cleanup);
6373     esp++;
6374     /* variable to hold stack depth for tint transform */
6375     make_int(&esp[0], 0);
6376     esp++;
6377     /* Store the 'base' type color wanted, in this case Gray */
6378     make_int(&esp[0], 0);
6379     make_int(&esp[1], 1);
6380     /* Store the 'stage' of processing (initially 0) */
6381     make_int(&esp[2], 0);
6382     /* Store a pointer to the color space stored on the operand stack
6383      * as the stack may grow unpredictably making further access
6384      * to the space difficult
6385      */
6386     esp[3] = istate->colorspace[0].array;
6387     esp += 3; /* The push_op_estack macro increments esp before using it */
6388     /* Finally, the actual continuation routine */
6389     push_op_estack(currentbasecolor_cont);
6390     return o_push_estack;
6391 }
6392 static int
zcurrenthsbcolor(i_ctx_t * i_ctx_p)6393 zcurrenthsbcolor(i_ctx_t * i_ctx_p)
6394 {
6395     int code, depth;
6396 
6397     code = validate_spaces(i_ctx_p, &istate->colorspace[0].array, &depth);
6398     if (code < 0)
6399         return code;
6400 
6401     code = zcurrentcolor(i_ctx_p);
6402     if (code < 0)
6403         return code;
6404     /* Set up for the continuation procedure which will do the work */
6405     /* Make sure the exec stack has enough space */
6406     check_estack(7);
6407     push_mark_estack(es_other, colour_cleanup);
6408     esp++;
6409     /* variable to hold stack depth for tint transform */
6410     make_int(&esp[0], 0);
6411     esp++;
6412     /* Store the 'base' type color wanted, in this case HSB */
6413     make_int(&esp[0], 1);
6414     make_int(&esp[1], 1);
6415     /* Store the 'stage' of processing (initially 0) */
6416     make_int(&esp[2], 0);
6417     /* Store a pointer to the color space stored on the operand stack
6418      * as the stack may grow unpredictably making further access
6419      * to the space difficult
6420      */
6421     esp[3] = istate->colorspace[0].array;
6422     esp += 3; /* The push_op_estack macro increments esp before using it */
6423     /* Finally, the actual continuation routine */
6424     push_op_estack(currentbasecolor_cont);
6425     return o_push_estack;
6426 }
6427 static int
zcurrentrgbcolor(i_ctx_t * i_ctx_p)6428 zcurrentrgbcolor(i_ctx_t * i_ctx_p)
6429 {
6430     int code;
6431 
6432     code = zcurrentcolor(i_ctx_p);
6433     if (code < 0)
6434         return code;
6435     /* Set up for the continuation procedure which will do the work */
6436     /* Make sure the exec stack has enough space */
6437     check_estack(7);
6438     push_mark_estack(es_other, colour_cleanup);
6439     esp++;
6440     /* variable to hold stack depth for tint transform */
6441     make_int(&esp[0], 0);
6442     esp++;
6443     /* Store the 'base' type color wanted, in this case RGB */
6444     make_int(&esp[0], 2);
6445     make_int(&esp[1], 1);
6446     /* Store the 'stage' of processing (initially 0) */
6447     make_int(&esp[2], 0);
6448     /* Store a pointer to the color space stored on the operand stack
6449      * as the stack may grow unpredictably making further access
6450      * to the space difficult
6451      */
6452     esp[3] = istate->colorspace[0].array;
6453     esp += 3; /* The push_op_estack macro increments esp before using it */
6454     /* Finally, the actual continuation routine */
6455     push_op_estack(currentbasecolor_cont);
6456     return o_push_estack;
6457 }
6458 static int
zcurrentcmykcolor(i_ctx_t * i_ctx_p)6459 zcurrentcmykcolor(i_ctx_t * i_ctx_p)
6460 {
6461     int code;
6462 
6463     code = zcurrentcolor(i_ctx_p);
6464     if (code < 0)
6465         return code;
6466     /* Set up for the continuation procedure which will do the work */
6467     /* Make sure the exec stack has enough space */
6468     check_estack(7);
6469     push_mark_estack(es_other, colour_cleanup);
6470     esp++;
6471     /* variable to hold stack depth for tint transform */
6472     make_int(&esp[0], 0);
6473     esp++;
6474     /* Store the 'base' type color wanted, in this case CMYK */
6475     make_int(&esp[0], 3);
6476     make_int(&esp[1], 1);
6477     /* Store the 'stage' of processing (initially 0) */
6478     make_int(&esp[2], 0);
6479     /* Store a pointer to the color space stored on the operand stack
6480      * as the stack may grow unpredictably making further access
6481      * to the space difficult
6482      */
6483     esp[3] = istate->colorspace[0].array;
6484     esp += 3; /* The push_op_estack macro increments esp before using it */
6485     /* Finally, the actual continuation routine */
6486     push_op_estack(currentbasecolor_cont);
6487     return o_push_estack;
6488 }
6489 
6490 static int
zswapcolors(i_ctx_t * i_ctx_p)6491 zswapcolors(i_ctx_t * i_ctx_p)
6492 {
6493     ref_colorspace tmp_cs;
6494     ref            tmp_pat;
6495 
6496     tmp_cs                = istate->colorspace[0];
6497     istate->colorspace[0] = istate->colorspace[1];
6498     istate->colorspace[1] = tmp_cs;
6499 
6500     tmp_pat            = istate->pattern[0];
6501     istate->pattern[0] = istate->pattern[1];
6502     istate->pattern[1] = tmp_pat;
6503 
6504     return gs_swapcolors(igs);
6505 }
6506 
6507 /* ------ Initialization procedure ------ */
6508 
6509 /* We need to split the table because of the 16-element limit. */
6510 const op_def    zcolor_op_defs[] =
6511 {
6512     { "0currentcolor", zcurrentcolor },
6513     { "0currentcolorspace", zcurrentcolorspace },
6514     { "0.getuseciecolor", zgetuseciecolor },
6515     { "1setcolor", zsetcolor },
6516     { "1setcolorspace", zsetcolorspace },
6517 
6518     /* basic transfer operators */
6519     { "0currenttransfer", zcurrenttransfer },
6520     { "0processcolors", zprocesscolors },
6521     { "1settransfer", zsettransfer },
6522 
6523     /* internal operators */
6524     { "1%zcolor_remap_one_finish", zcolor_remap_one_finish },
6525     { "1%zcolor_remap_one_signed_finish", zcolor_remap_one_signed_finish },
6526     { "0%zcolor_reset_transfer", zcolor_reset_transfer },
6527     { "0%zcolor_remap_color", zcolor_remap_color },
6528     { "0.color_test", zcolor_test },
6529     { "1.color_test_all", zcolor_test_all },
6530 
6531     /* high level device support */
6532     { "0.includecolorspace", zincludecolorspace },
6533     op_def_end(0)
6534 };
6535 
6536 const op_def    zcolor_ext_op_defs[] =
6537 {
6538     { "0currentgray", zcurrentgray },
6539     { "1setgray", zsetgray },
6540     { "0currenthsbcolor", zcurrenthsbcolor },
6541     { "3sethsbcolor", zsethsbcolor },
6542     { "0currentrgbcolor", zcurrentrgbcolor },
6543     { "3setrgbcolor", zsetrgbcolor },
6544     { "0currentcmykcolor", zcurrentcmykcolor },
6545     { "4setcmykcolor", zsetcmykcolor },
6546 
6547     /* Operators to deal with setting stroking/non-stroking colors
6548      * individually */
6549     { "1.swapcolors", zswapcolors },
6550 
6551     /* internal operators, entries here only used for error reporting */
6552     { "0%setcolorspace_cont", setcolorspace_cont },
6553     { "0%setcolor_cont", setcolor_cont },
6554     { "0%devicencolorants_cont", devicencolorants_cont },
6555     { "0%indexed_cont", indexed_cont },
6556     { "0%setdevicecolor_cont", setdevicecolor_cont },
6557     { "0%currentbasecolor_cont", currentbasecolor_cont },
6558 op_def_end(0)
6559 };
6560