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 /* Common utilities for PostScript and PDF format printing */
18 #include "stdio_.h"		/* for stream.h */
19 #include "string_.h"
20 #include "gstypes.h"
21 #include "gsmemory.h"
22 #include "gserrors.h"
23 #include "spprint.h"
24 #include "spsdf.h"
25 #include "stream.h"
26 #include "strimpl.h"
27 #include "sa85x.h"
28 #include "sstring.h"
29 #include "scanchar.h"
30 
31 /*
32  * Write a string in its shortest form ( () or <> ).  Note that
33  * this form is different depending on whether binary data are allowed.
34  * Currently we don't support ASCII85 strings ( <~ ~> ).
35  */
36 void
s_write_ps_string(stream * s,const byte * str,uint size,int print_ok)37 s_write_ps_string(stream * s, const byte * str, uint size, int print_ok)
38 {
39     uint added = 0;
40     uint i;
41     const stream_template *templat;
42     stream_AXE_state state;
43     stream_state *st = NULL;
44 
45     if (print_ok & PRINT_BINARY_OK) {
46         /* Only need to escape (, ), \, CR, EOL. */
47         stream_putc(s, '(');
48         for (i = 0; i < size; ++i) {
49             byte ch = str[i];
50 
51             switch (ch) {
52                 case char_CR:
53                     stream_puts(s, "\\r");
54                     continue;
55                 case char_EOL:
56                     stream_puts(s, "\\n");
57                     continue;
58                 case '(':
59                 case ')':
60                 case '\\':
61                     stream_putc(s, '\\');
62             }
63             stream_putc(s, ch);
64         }
65         stream_putc(s, ')');
66         return;
67     }
68     for (i = 0; i < size; ++i) {
69         byte ch = str[i];
70 
71         if (ch == 0 || ch >= 127)
72             added += 3;
73         else if (strchr("()\\\n\r\t\b\f", ch) != 0)
74             ++added;
75         else if (ch < 32)
76             added += 3;
77     }
78 
79     if (added < size || (print_ok & PRINT_HEX_NOT_OK)) {
80         /* More efficient, or mandatory, to represent as PostScript string. */
81         templat = &s_PSSE_template;
82         stream_putc(s, '(');
83     } else {
84         /* More efficient, and permitted, to represent as hex string. */
85         templat = &s_AXE_template;
86         st = (stream_state *) & state;
87         s_AXE_init_inline(&state);
88         stream_putc(s, '<');
89     }
90 
91     {
92         byte buf[100];		/* size is arbitrary */
93         stream_cursor_read r;
94         stream_cursor_write w;
95         int status;
96 
97         r.ptr = str - 1;
98         r.limit = r.ptr + size;
99         w.limit = buf + sizeof(buf) - 1;
100         do {
101             /* One picky compiler complains if we initialize to buf - 1. */
102             w.ptr = buf;  w.ptr--;
103             status = (*templat->process) (st, &r, &w, true);
104             stream_write(s, buf, (uint) (w.ptr + 1 - buf));
105         }
106         while (status == 1);
107     }
108 }
109 
110 /* Set up a write stream that just keeps track of the position. */
111 int
s_alloc_position_stream(stream ** ps,gs_memory_t * mem)112 s_alloc_position_stream(stream ** ps, gs_memory_t * mem)
113 {
114     stream *s = *ps = s_alloc(mem, "s_alloc_position_stream");
115 
116     if (s == 0)
117         return_error(gs_error_VMerror);
118     swrite_position_only(s);
119     return 0;
120 }
121 
122 /* ---------------- Parameter printing ---------------- */
123 
124 private_st_printer_param_list();
125 const param_printer_params_t param_printer_params_default = {
126     param_printer_params_default_values
127 };
128 
129 /* We'll implement the other printers later if we have to. */
130 static param_proc_xmit_typed(param_print_typed);
131 /*static param_proc_begin_xmit_collection(param_print_begin_collection);*/
132 /*static param_proc_end_xmit_collection(param_print_end_collection);*/
133 static const gs_param_list_procs printer_param_list_procs = {
134     param_print_typed,
135     NULL /* begin_collection */ ,
136     NULL /* end_collection */ ,
137     NULL /* get_next_key */ ,
138     gs_param_request_default,
139     gs_param_requested_default
140 };
141 
142 int
s_init_param_printer(printer_param_list_t * prlist,const param_printer_params_t * ppp,stream * s)143 s_init_param_printer(printer_param_list_t *prlist,
144                      const param_printer_params_t * ppp, stream * s)
145 {
146     gs_param_list_init((gs_param_list *)prlist, &printer_param_list_procs,
147                        NULL);
148     prlist->strm = s;
149     prlist->params = *ppp;
150     prlist->any = false;
151     return 0;
152 }
153 int
s_alloc_param_printer(gs_param_list ** pplist,const param_printer_params_t * ppp,stream * s,gs_memory_t * mem)154 s_alloc_param_printer(gs_param_list ** pplist,
155                       const param_printer_params_t * ppp, stream * s,
156                       gs_memory_t * mem)
157 {
158     printer_param_list_t *prlist =
159         gs_alloc_struct(mem, printer_param_list_t, &st_printer_param_list,
160                         "s_alloc_param_printer");
161     int code;
162 
163     *pplist = (gs_param_list *)prlist;
164     if (prlist == 0)
165         return_error(gs_error_VMerror);
166     code = s_init_param_printer(prlist, ppp, s);
167     prlist->memory = mem;
168     return code;
169 }
170 
171 void
s_release_param_printer(printer_param_list_t * prlist)172 s_release_param_printer(printer_param_list_t *prlist)
173 {
174     if (prlist) {
175         if (prlist->any && prlist->params.suffix)
176             stream_puts(prlist->strm, prlist->params.suffix);
177     }
178 }
179 void
s_free_param_printer(gs_param_list * plist)180 s_free_param_printer(gs_param_list * plist)
181 {
182     if (plist) {
183         printer_param_list_t *const prlist = (printer_param_list_t *) plist;
184 
185         s_release_param_printer(prlist);
186         gs_free_object(prlist->memory, plist, "s_free_param_printer");
187     }
188 }
189 
190 static int
param_print_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)191 param_print_typed(gs_param_list * plist, gs_param_name pkey,
192                   gs_param_typed_value * pvalue)
193 {
194     printer_param_list_t *const prlist = (printer_param_list_t *)plist;
195     stream *s = prlist->strm;
196 
197     if (!prlist->any) {
198         if (prlist->params.prefix)
199             stream_puts(s, prlist->params.prefix);
200         prlist->any = true;
201     }
202     if (prlist->params.item_prefix)
203         stream_puts(s, prlist->params.item_prefix);
204     pprints1(s, "/%s", pkey);
205     switch (pvalue->type) {
206         case gs_param_type_null:
207             stream_puts(s, " null");
208             break;
209         case gs_param_type_bool:
210             stream_puts(s, (pvalue->value.b ? " true" : " false"));
211             break;
212         case gs_param_type_int:
213             pprintd1(s, " %d", pvalue->value.i);
214             break;
215         case gs_param_type_long:
216             pprintld1(s, " %l", pvalue->value.l);
217             break;
218         case gs_param_type_float:
219             pprintg1(s, " %g", pvalue->value.f);
220             break;
221         case gs_param_type_string:
222             s_write_ps_string(s, pvalue->value.s.data, pvalue->value.s.size,
223                               prlist->params.print_ok);
224             break;
225         case gs_param_type_name:
226             /****** SHOULD USE #-ESCAPES FOR PDF ******/
227             stream_putc(s, '/');
228             stream_write(s, pvalue->value.n.data, pvalue->value.n.size);
229             break;
230         case gs_param_type_int_array:
231             {
232                 uint i;
233                 char sepr = (pvalue->value.ia.size <= 10 ? ' ' : '\n');
234 
235                 stream_putc(s, '[');
236                 for (i = 0; i < pvalue->value.ia.size; ++i) {
237                     pprintd1(s, "%d", pvalue->value.ia.data[i]);
238                     stream_putc(s, sepr);
239                 }
240                 stream_putc(s, ']');
241             }
242             break;
243         case gs_param_type_float_array:
244             {
245                 uint i;
246                 char sepr = (pvalue->value.fa.size <= 10 ? ' ' : '\n');
247 
248                 stream_putc(s, '[');
249                 for (i = 0; i < pvalue->value.fa.size; ++i) {
250                     pprintg1(s, "%g", pvalue->value.fa.data[i]);
251                     stream_putc(s, sepr);
252                 }
253                 stream_putc(s, ']');
254             }
255             break;
256             /*case gs_param_type_string_array: */
257             /*case gs_param_type_name_array: */
258         default:
259             return_error(gs_error_typecheck);
260     }
261     if (prlist->params.item_suffix)
262         stream_puts(s, prlist->params.item_suffix);
263     return 0;
264 }
265