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