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