Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
};