1 /* Copyright (C) 1998, 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: zfrsd.c,v 1.10 2004/08/04 19:36:13 stefan Exp $ */
18 /* ReusableStreamDecode filter support */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "gsfname.h" /* for gs_parse_file_name */
22 #include "gxiodev.h"
23 #include "oper.h"
24 #include "stream.h"
25 #include "strimpl.h"
26 #include "sfilter.h" /* for SubFileDecode */
27 #include "files.h"
28 #include "idict.h"
29 #include "idparam.h"
30 #include "iname.h"
31 #include "store.h"
32
33 /* ---------------- Reusable streams ---------------- */
34
35 /*
36 * The actual work of constructing the filter is done in PostScript code.
37 * The operators in this file are internal ones that handle the dirty work.
38 */
39
40 /* <dict|null> .rsdparams <filters> <decodeparms|null> */
41 /* filters is always an array; decodeparms is always either an array */
42 /* of the same length as filters, or null. */
43 private int
zrsdparams(i_ctx_t * i_ctx_p)44 zrsdparams(i_ctx_t *i_ctx_p)
45 {
46 os_ptr op = osp;
47 ref *pFilter;
48 ref *pDecodeParms;
49 int Intent;
50 bool AsyncRead;
51 ref empty_array, filter1_array, parms1_array;
52 uint i;
53 int code;
54
55 make_empty_array(&empty_array, a_readonly);
56 if (dict_find_string(op, "Filter", &pFilter) > 0) {
57 if (!r_is_array(pFilter)) {
58 if (!r_has_type(pFilter, t_name))
59 return_error(e_typecheck);
60 make_array(&filter1_array, a_readonly, 1, pFilter);
61 pFilter = &filter1_array;
62 }
63 } else
64 pFilter = &empty_array;
65 /* If Filter is undefined, ignore DecodeParms. */
66 if (pFilter != &empty_array &&
67 dict_find_string(op, "DecodeParms", &pDecodeParms) > 0
68 ) {
69 if (pFilter == &filter1_array) {
70 make_array(&parms1_array, a_readonly, 1, pDecodeParms);
71 pDecodeParms = &parms1_array;
72 } else if (!r_is_array(pDecodeParms))
73 return_error(e_typecheck);
74 else if (r_size(pFilter) != r_size(pDecodeParms))
75 return_error(e_rangecheck);
76 } else
77 pDecodeParms = 0;
78 for (i = 0; i < r_size(pFilter); ++i) {
79 ref f, fname, dp;
80
81 array_get(imemory, pFilter, (long)i, &f);
82 if (!r_has_type(&f, t_name))
83 return_error(e_typecheck);
84 name_string_ref(imemory, &f, &fname);
85 if (r_size(&fname) < 6 ||
86 memcmp(fname.value.bytes + r_size(&fname) - 6, "Decode", 6)
87 )
88 return_error(e_rangecheck);
89 if (pDecodeParms) {
90 array_get(imemory, pDecodeParms, (long)i, &dp);
91 if (!(r_has_type(&dp, t_dictionary) || r_has_type(&dp, t_null)))
92 return_error(e_typecheck);
93 }
94 }
95 if ((code = dict_int_param(op, "Intent", 0, 3, 0, &Intent)) < 0 ||
96 (code = dict_bool_param(op, "AsyncRead", false, &AsyncRead)) < 0
97 )
98 return code;
99 push(1);
100 op[-1] = *pFilter;
101 if (pDecodeParms)
102 *op = *pDecodeParms;
103 else
104 make_null(op);
105 return 0;
106 }
107
108 /* <file|string> <CloseSource> .reusablestream <filter> */
109 /*
110 * The file|string operand must be a "reusable source", either:
111 * - A string or bytestring;
112 * - A readable, positionable file stream;
113 * - A readable string stream;
114 * - A SubFileDecode filter with an empty EODString and a reusable
115 * source.
116 * Reusable streams are also reusable sources, but they look just like
117 * ordinary file or string streams.
118 */
119 private int make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data,
120 uint size, int space, long offset, long length,
121 bool is_bytestring);
122 private int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs,
123 long offset, long length);
124 private int
zreusablestream(i_ctx_t * i_ctx_p)125 zreusablestream(i_ctx_t *i_ctx_p)
126 {
127 os_ptr op = osp;
128 os_ptr source_op = op - 1;
129 long length = max_long;
130 bool close_source;
131 int code;
132
133 check_type(*op, t_boolean);
134 close_source = op->value.boolval;
135 if (r_has_type(source_op, t_string)) {
136 uint size = r_size(source_op);
137
138 check_read(*source_op);
139 code = make_rss(i_ctx_p, source_op, source_op->value.const_bytes,
140 size, r_space(source_op), 0L, size, false);
141 } else if (r_has_type(source_op, t_astruct)) {
142 uint size = gs_object_size(imemory, source_op->value.pstruct);
143
144 if (gs_object_type(imemory, source_op->value.pstruct) != &st_bytes)
145 return_error(e_rangecheck);
146 check_read(*source_op);
147 code = make_rss(i_ctx_p, source_op,
148 (const byte *)source_op->value.pstruct, size,
149 r_space(source_op), 0L, size, true);
150 } else {
151 long offset = 0;
152 stream *source;
153 stream *s;
154
155 check_read_file(source, source_op);
156 s = source;
157 rs:
158 if (s->cbuf_string.data != 0) { /* string stream */
159 long pos = stell(s);
160 long avail = sbufavailable(s) + pos;
161
162 offset += pos;
163 code = make_rss(i_ctx_p, source_op, s->cbuf_string.data,
164 s->cbuf_string.size,
165 imemory_space((const gs_ref_memory_t *)s->memory),
166 offset, min(avail, length), false);
167 } else if (s->file != 0) { /* file stream */
168 if (~s->modes & (s_mode_read | s_mode_seek))
169 return_error(e_ioerror);
170 code = make_rfs(i_ctx_p, source_op, s, offset + stell(s), length);
171 } else if (s->state->template == &s_SFD_template) {
172 /* SubFileDecode filter */
173 const stream_SFD_state *const sfd_state =
174 (const stream_SFD_state *)s->state;
175
176 if (sfd_state->eod.size != 0)
177 return_error(e_rangecheck);
178 offset += sfd_state->skip_count - sbufavailable(s);
179 if (sfd_state->count != 0) {
180 long left = max(sfd_state->count, 0) + sbufavailable(s);
181
182 if (left < length)
183 length = left;
184 }
185 s = s->strm;
186 goto rs;
187 }
188 else /* some other kind of stream */
189 return_error(e_rangecheck);
190 if (close_source) {
191 stream *rs = fptr(source_op);
192
193 rs->strm = source; /* only for close_source */
194 rs->close_strm = true;
195 }
196 }
197 if (code >= 0)
198 pop(1);
199 return code;
200 }
201
202 /* Make a reusable string stream. */
203 private int
make_rss(i_ctx_t * i_ctx_p,os_ptr op,const byte * data,uint size,int string_space,long offset,long length,bool is_bytestring)204 make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size,
205 int string_space, long offset, long length, bool is_bytestring)
206 {
207 stream *s;
208 long left = min(length, size - offset);
209
210 if (icurrent_space < string_space)
211 return_error(e_invalidaccess);
212 s = file_alloc_stream(imemory, "make_rss");
213 if (s == 0)
214 return_error(e_VMerror);
215 sread_string_reusable(s, data + offset, max(left, 0));
216 if (is_bytestring)
217 s->cbuf_string.data = 0; /* byte array, not string */
218 make_stream_file(op, s, "r");
219 return 0;
220 }
221
222 /* Make a reusable file stream. */
223 private int
make_rfs(i_ctx_t * i_ctx_p,os_ptr op,stream * fs,long offset,long length)224 make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length)
225 {
226 gs_const_string fname;
227 gs_parsed_file_name_t pname;
228 stream *s;
229 int code;
230
231 if (sfilename(fs, &fname) < 0)
232 return_error(e_ioerror);
233 code = gs_parse_file_name(&pname, (const char *)fname.data, fname.size);
234 if (code < 0)
235 return code;
236 if (pname.len == 0) /* %stdin% etc. won't have a filename */
237 return_error(e_invalidfileaccess); /* can't reopen */
238 if (pname.iodev == NULL)
239 pname.iodev = iodev_default;
240 /* Open the file again, to be independent of the source. */
241 code = file_open_stream((const char *)pname.fname, pname.len, "r",
242 fs->cbsize, &s, pname.iodev,
243 pname.iodev->procs.fopen, imemory);
244 if (code < 0)
245 return code;
246 if (sread_subfile(s, offset, length) < 0) {
247 sclose(s);
248 return_error(e_ioerror);
249 }
250 s->close_at_eod = false;
251 make_stream_file(op, s, "r");
252 return 0;
253 }
254
255 /* ---------------- Initialization procedure ---------------- */
256
257 const op_def zfrsd_op_defs[] =
258 {
259 {"2.reusablestream", zreusablestream},
260 {"2.rsdparams", zrsdparams},
261 op_def_end(0)
262 };
263