1 /* Copyright (C) 1993, 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: zfilter.c,v 1.10 2004/01/17 20:46:32 dan Exp $ */
18 /* Filter creation */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsstruct.h"
23 #include "ialloc.h"
24 #include "idict.h"
25 #include "idparam.h"
26 #include "ilevel.h" /* SubFileDecode is different in LL3 */
27 #include "stream.h"
28 #include "strimpl.h"
29 #include "sfilter.h"
30 #include "srlx.h"
31 #include "sstring.h"
32 #include "ifilter.h"
33 #include "files.h" /* for filter_open, file_d'_buffer_size */
34
35 /* <source> ASCIIHexEncode/filter <file> */
36 /* <source> <dict> ASCIIHexEncode/filter <file> */
37 private int
zAXE(i_ctx_t * i_ctx_p)38 zAXE(i_ctx_t *i_ctx_p)
39 {
40 return filter_write_simple(i_ctx_p, &s_AXE_template);
41 }
42
43 /* <target> ASCIIHexDecode/filter <file> */
44 /* <target> <dict> ASCIIHexDecode/filter <file> */
45 private int
zAXD(i_ctx_t * i_ctx_p)46 zAXD(i_ctx_t *i_ctx_p)
47 {
48 return filter_read_simple(i_ctx_p, &s_AXD_template);
49 }
50
51 /* <target> NullEncode/filter <file> */
52 /* <target> <dict_ignored> NullEncode/filter <file> */
53 private int
zNullE(i_ctx_t * i_ctx_p)54 zNullE(i_ctx_t *i_ctx_p)
55 {
56 return filter_write_simple(i_ctx_p, &s_NullE_template);
57 }
58
59 /* <source> <bool> PFBDecode/filter <file> */
60 /* <source> <dict> <bool> PFBDecode/filter <file> */
61 private int
zPFBD(i_ctx_t * i_ctx_p)62 zPFBD(i_ctx_t *i_ctx_p)
63 {
64 os_ptr sop = osp;
65 stream_PFBD_state state;
66
67 check_type(*sop, t_boolean);
68 state.binary_to_hex = sop->value.boolval;
69 return filter_read(i_ctx_p, 1, &s_PFBD_template, (stream_state *)&state, 0);
70 }
71
72 /* <target> PSStringEncode/filter <file> */
73 /* <target> <dict> PSStringEncode/filter <file> */
74 private int
zPSSE(i_ctx_t * i_ctx_p)75 zPSSE(i_ctx_t *i_ctx_p)
76 {
77 return filter_write_simple(i_ctx_p, &s_PSSE_template);
78 }
79
80 /* ------ RunLength filters ------ */
81
82 /* Common setup for RLE and RLD filters. */
83 private int
rl_setup(os_ptr dop,bool * eod)84 rl_setup(os_ptr dop, bool * eod)
85 {
86 if (r_has_type(dop, t_dictionary)) {
87 int code;
88
89 check_dict_read(*dop);
90 if ((code = dict_bool_param(dop, "EndOfData", true, eod)) < 0)
91 return code;
92 return 1;
93 } else {
94 *eod = true;
95 return 0;
96 }
97 }
98
99 /* <target> <record_size> RunLengthEncode/filter <file> */
100 /* <target> <dict> <record_size> RunLengthEncode/filter <file> */
101 private int
zRLE(i_ctx_t * i_ctx_p)102 zRLE(i_ctx_t *i_ctx_p)
103 {
104 os_ptr op = osp;
105 stream_RLE_state state;
106 int code;
107
108 check_op(2);
109 code = rl_setup(op - 1, &state.EndOfData);
110 if (code < 0)
111 return code;
112 check_int_leu(*op, max_uint);
113 state.record_size = op->value.intval;
114 return filter_write(i_ctx_p, 1, &s_RLE_template, (stream_state *) & state, 0);
115 }
116
117 /* <source> RunLengthDecode/filter <file> */
118 /* <source> <dict> RunLengthDecode/filter <file> */
119 private int
zRLD(i_ctx_t * i_ctx_p)120 zRLD(i_ctx_t *i_ctx_p)
121 {
122 os_ptr op = osp;
123 stream_RLD_state state;
124 int code = rl_setup(op, &state.EndOfData);
125
126 if (code < 0)
127 return code;
128 return filter_read(i_ctx_p, 0, &s_RLD_template, (stream_state *) & state, 0);
129 }
130
131 /* <source> <EODcount> <EODstring> SubFileDecode/filter <file> */
132 /* <source> <dict> <EODcount> <EODstring> SubFileDecode/filter <file> */
133 /* <source> <dict> SubFileDecode/filter <file> *//* (LL3 only) */
134 private int
zSFD(i_ctx_t * i_ctx_p)135 zSFD(i_ctx_t *i_ctx_p)
136 {
137 os_ptr op = osp;
138 stream_SFD_state state;
139 ref *sop = op;
140 int npop;
141
142 if (s_SFD_template.set_defaults)
143 s_SFD_template.set_defaults((stream_state *)&state);
144 if (LL3_ENABLED && r_has_type(op, t_dictionary)) {
145 int count;
146 int code;
147
148 check_dict_read(*op);
149 /*
150 * The PLRM-3rd says that EODCount is a required parameter. However
151 * Adobe accepts files without this value and apparently defaults to
152 * zero. Thus we are doing the same.
153 */
154 if ((code = dict_int_param(op, "EODCount", 0, max_int, 0, &count)) < 0)
155 return code;
156 if (dict_find_string(op, "EODString", &sop) <= 0)
157 return_error(e_rangecheck);
158 state.count = count;
159 npop = 0;
160 } else {
161 check_type(sop[-1], t_integer);
162 if (sop[-1].value.intval < 0)
163 return_error(e_rangecheck);
164 state.count = sop[-1].value.intval;
165 npop = 2;
166 }
167 check_read_type(*sop, t_string);
168 state.eod.data = sop->value.const_bytes;
169 state.eod.size = r_size(sop);
170 return filter_read(i_ctx_p, npop, &s_SFD_template,
171 (stream_state *)&state, r_space(sop));
172 }
173
174 /* ------ Utilities ------ */
175
176 /* Forward references */
177 private int filter_ensure_buf(stream **, uint, gs_ref_memory_t *, bool);
178
179 /* Set up an input filter. */
180 int
filter_read(i_ctx_t * i_ctx_p,int npop,const stream_template * template,stream_state * st,uint space)181 filter_read(i_ctx_t *i_ctx_p, int npop, const stream_template * template,
182 stream_state * st, uint space)
183 {
184 os_ptr op = osp;
185 uint min_size = template->min_out_size + max_min_left;
186 uint save_space = ialloc_space(idmemory);
187 uint use_space = max(space, save_space);
188 os_ptr sop = op - npop;
189 stream *s;
190 stream *sstrm;
191 bool close = false;
192 int code;
193
194 /* Skip over an optional dictionary parameter. */
195 if (r_has_type(sop, t_dictionary)) {
196 check_dict_read(*sop);
197 if ((code = dict_bool_param(sop, "CloseSource", false, &close)) < 0)
198 return code;
199 --sop;
200 }
201 /*
202 * Check to make sure that the underlying data
203 * can function as a source for reading.
204 */
205 use_space = max(use_space, r_space(sop));
206 switch (r_type(sop)) {
207 case t_string:
208 check_read(*sop);
209 ialloc_set_space(idmemory, use_space);
210 sstrm = file_alloc_stream(imemory, "filter_read(string stream)");
211 if (sstrm == 0) {
212 code = gs_note_error(e_VMerror);
213 goto out;
214 }
215 sread_string(sstrm, sop->value.bytes, r_size(sop));
216 sstrm->is_temp = 1;
217 break;
218 case t_file:
219 check_read_known_file(sstrm, sop, return);
220 ialloc_set_space(idmemory, use_space);
221 goto ens;
222 default:
223 check_proc(*sop);
224 ialloc_set_space(idmemory, use_space);
225 code = sread_proc(sop, &sstrm, iimemory);
226 if (code < 0)
227 goto out;
228 sstrm->is_temp = 2;
229 ens:
230 code = filter_ensure_buf(&sstrm,
231 template->min_in_size +
232 sstrm->state->template->min_out_size,
233 iimemory, false);
234 if (code < 0)
235 goto out;
236 break;
237 }
238 if (min_size < 128)
239 min_size = file_default_buffer_size;
240 code = filter_open("r", min_size, (ref *) sop,
241 &s_filter_read_procs, template, st, imemory);
242 if (code < 0)
243 goto out;
244 s = fptr(sop);
245 s->strm = sstrm;
246 s->close_strm = close;
247 pop(op - sop);
248 out:
249 ialloc_set_space(idmemory, save_space);
250 return code;
251 }
252 int
filter_read_simple(i_ctx_t * i_ctx_p,const stream_template * template)253 filter_read_simple(i_ctx_t *i_ctx_p, const stream_template * template)
254 {
255 return filter_read(i_ctx_p, 0, template, NULL, 0);
256 }
257
258 /* Set up an output filter. */
259 int
filter_write(i_ctx_t * i_ctx_p,int npop,const stream_template * template,stream_state * st,uint space)260 filter_write(i_ctx_t *i_ctx_p, int npop, const stream_template * template,
261 stream_state * st, uint space)
262 {
263 os_ptr op = osp;
264 uint min_size = template->min_in_size + max_min_left;
265 uint save_space = ialloc_space(idmemory);
266 uint use_space = max(space, save_space);
267 register os_ptr sop = op - npop;
268 stream *s;
269 stream *sstrm;
270 bool close = false;
271 int code;
272
273 /* Skip over an optional dictionary parameter. */
274 if (r_has_type(sop, t_dictionary)) {
275 check_dict_read(*sop);
276 if ((code = dict_bool_param(sop, "CloseTarget", false, &close)) < 0)
277 return code;
278 --sop;
279 }
280 /*
281 * Check to make sure that the underlying data
282 * can function as a sink for writing.
283 */
284 use_space = max(use_space, r_space(sop));
285 switch (r_type(sop)) {
286 case t_string:
287 check_write(*sop);
288 ialloc_set_space(idmemory, use_space);
289 sstrm = file_alloc_stream(imemory, "filter_write(string)");
290 if (sstrm == 0) {
291 code = gs_note_error(e_VMerror);
292 goto out;
293 }
294 swrite_string(sstrm, sop->value.bytes, r_size(sop));
295 sstrm->is_temp = 1;
296 break;
297 case t_file:
298 check_write_known_file(sstrm, sop, return);
299 ialloc_set_space(idmemory, use_space);
300 goto ens;
301 default:
302 check_proc(*sop);
303 ialloc_set_space(idmemory, use_space);
304 code = swrite_proc(sop, &sstrm, iimemory);
305 if (code < 0)
306 goto out;
307 sstrm->is_temp = 2;
308 ens:
309 code = filter_ensure_buf(&sstrm,
310 template->min_out_size +
311 sstrm->state->template->min_in_size,
312 iimemory, true);
313 if (code < 0)
314 goto out;
315 break;
316 }
317 if (min_size < 128)
318 min_size = file_default_buffer_size;
319 code = filter_open("w", min_size, (ref *) sop,
320 &s_filter_write_procs, template, st, imemory);
321 if (code < 0)
322 goto out;
323 s = fptr(sop);
324 s->strm = sstrm;
325 s->close_strm = close;
326 pop(op - sop);
327 out:
328 ialloc_set_space(idmemory, save_space);
329 return code;
330 }
331 int
filter_write_simple(i_ctx_t * i_ctx_p,const stream_template * template)332 filter_write_simple(i_ctx_t *i_ctx_p, const stream_template * template)
333 {
334 return filter_write(i_ctx_p, 0, template, NULL, 0);
335 }
336
337 /* Define a byte-at-a-time NullDecode filter for intermediate buffers. */
338 /* (The standard NullDecode filter can read ahead too far.) */
339 private int
s_Null1D_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)340 s_Null1D_process(stream_state * st, stream_cursor_read * pr,
341 stream_cursor_write * pw, bool last)
342 {
343 if (pr->ptr >= pr->limit)
344 return 0;
345 if (pw->ptr >= pw->limit)
346 return 1;
347 *++(pw->ptr) = *++(pr->ptr);
348 return 1;
349 }
350 private const stream_template s_Null1D_template = {
351 &st_stream_state, NULL, s_Null1D_process, 1, 1
352 };
353
354 /* A utility filter that returns an immediate EOF without consuming */
355 /* any data from its source. Used by PDF interpreter for unknown */
356 /* filter types. */
357 private int
s_EOFD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)358 s_EOFD_process(stream_state * st, stream_cursor_read * pr,
359 stream_cursor_write * pw, bool last)
360 {
361 return EOFC;
362 }
363 private const stream_template s_EOFD_template = {
364 &st_stream_state, NULL, s_EOFD_process, 1, 1
365 };
366
367 /* <target> /.EOFDecode filter <file> */
368 /* <target> <dict> /.EOFDecode filter <file> */
369 private int
zEOFD(i_ctx_t * i_ctx_p)370 zEOFD(i_ctx_t *i_ctx_p)
371 {
372 return filter_read_simple(i_ctx_p, &s_EOFD_template);
373 }
374
375
376 /* Ensure a minimum buffer size for a filter. */
377 /* This may require creating an intermediate stream. */
378 private int
filter_ensure_buf(stream ** ps,uint min_buf_size,gs_ref_memory_t * imem,bool writing)379 filter_ensure_buf(stream ** ps, uint min_buf_size, gs_ref_memory_t *imem,
380 bool writing)
381 {
382 stream *s = *ps;
383 uint min_size = min_buf_size + max_min_left;
384 stream *bs;
385 ref bsop;
386 int code;
387
388 if (s->modes == 0 /* stream is closed */ || s->bsize >= min_size)
389 return 0;
390 /* Otherwise, allocate an intermediate stream. */
391 if (s->cbuf == 0) {
392 /* This is a newly created procedure stream. */
393 /* Just allocate a buffer for it. */
394 uint len = max(min_size, 128);
395 byte *buf = gs_alloc_bytes((gs_memory_t *)imem, len,
396 "filter_ensure_buf");
397
398 if (buf == 0)
399 return_error(e_VMerror);
400 s->cbuf = buf;
401 s->srptr = s->srlimit = s->swptr = buf - 1;
402 s->swlimit = buf - 1 + len;
403 s->bsize = s->cbsize = len;
404 return 0;
405 } else {
406 /* Allocate an intermediate stream. */
407 if (writing)
408 code = filter_open("w", min_size, &bsop, &s_filter_write_procs,
409 &s_NullE_template, NULL, (gs_memory_t *)imem);
410 else
411 code = filter_open("r", min_size, &bsop, &s_filter_read_procs,
412 &s_Null1D_template, NULL, (gs_memory_t *)imem);
413 if (code < 0)
414 return code;
415 bs = fptr(&bsop);
416 bs->strm = s;
417 bs->is_temp = 2;
418 *ps = bs;
419 return code;
420 }
421 }
422
423 /* Mark a (filter) stream as temporary. */
424 /* We define this here to avoid importing stream.h into zf*.c. */
425 void
filter_mark_temp(const ref * fop,int is_temp)426 filter_mark_temp(const ref * fop, int is_temp)
427 {
428 fptr(fop)->is_temp = is_temp;
429 }
430
431 /* Mark the source or target of a filter as temporary, and propagate */
432 /* close_strm from the temporary stream to the filter. */
433 void
filter_mark_strm_temp(const ref * fop,int is_temp)434 filter_mark_strm_temp(const ref * fop, int is_temp)
435 {
436 stream *s = fptr(fop);
437 stream *strm = s->strm;
438
439 strm->is_temp = is_temp;
440 s->close_strm = strm->close_strm;
441 }
442
443 /* ------ Initialization procedure ------ */
444
445 const op_def zfilter_op_defs[] = {
446 /* We enter PSStringEncode and SubFileDecode (only) */
447 /* as separate operators. */
448 {"1.psstringencode", zPSSE},
449 {"2.subfiledecode", zSFD},
450 op_def_begin_filter(),
451 {"1ASCIIHexEncode", zAXE},
452 {"1ASCIIHexDecode", zAXD},
453 {"1NullEncode", zNullE},
454 {"2PFBDecode", zPFBD},
455 {"1PSStringEncode", zPSSE},
456 {"2RunLengthEncode", zRLE},
457 {"1RunLengthDecode", zRLD},
458 {"3SubFileDecode", zSFD},
459 {"1.EOFDecode", zEOFD},
460 op_def_end(0)
461 };
462