13ff48bf5SDavid du Colombier /* Copyright (C) 1998, 2000 Aladdin Enterprises. All rights reserved.
23ff48bf5SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
53ff48bf5SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: zfrsd.c,v 1.10 2004/08/04 19:36:13 stefan Exp $ */
183ff48bf5SDavid du Colombier /* ReusableStreamDecode filter support */
193ff48bf5SDavid du Colombier #include "memory_.h"
203ff48bf5SDavid du Colombier #include "ghost.h"
21*593dc095SDavid du Colombier #include "gsfname.h" /* for gs_parse_file_name */
223ff48bf5SDavid du Colombier #include "gxiodev.h"
233ff48bf5SDavid du Colombier #include "oper.h"
243ff48bf5SDavid du Colombier #include "stream.h"
253ff48bf5SDavid du Colombier #include "strimpl.h"
263ff48bf5SDavid du Colombier #include "sfilter.h" /* for SubFileDecode */
273ff48bf5SDavid du Colombier #include "files.h"
283ff48bf5SDavid du Colombier #include "idict.h"
293ff48bf5SDavid du Colombier #include "idparam.h"
303ff48bf5SDavid du Colombier #include "iname.h"
313ff48bf5SDavid du Colombier #include "store.h"
323ff48bf5SDavid du Colombier
333ff48bf5SDavid du Colombier /* ---------------- Reusable streams ---------------- */
343ff48bf5SDavid du Colombier
353ff48bf5SDavid du Colombier /*
363ff48bf5SDavid du Colombier * The actual work of constructing the filter is done in PostScript code.
373ff48bf5SDavid du Colombier * The operators in this file are internal ones that handle the dirty work.
383ff48bf5SDavid du Colombier */
393ff48bf5SDavid du Colombier
403ff48bf5SDavid du Colombier /* <dict|null> .rsdparams <filters> <decodeparms|null> */
413ff48bf5SDavid du Colombier /* filters is always an array; decodeparms is always either an array */
423ff48bf5SDavid du Colombier /* of the same length as filters, or null. */
433ff48bf5SDavid du Colombier private int
zrsdparams(i_ctx_t * i_ctx_p)443ff48bf5SDavid du Colombier zrsdparams(i_ctx_t *i_ctx_p)
453ff48bf5SDavid du Colombier {
463ff48bf5SDavid du Colombier os_ptr op = osp;
473ff48bf5SDavid du Colombier ref *pFilter;
483ff48bf5SDavid du Colombier ref *pDecodeParms;
493ff48bf5SDavid du Colombier int Intent;
503ff48bf5SDavid du Colombier bool AsyncRead;
513ff48bf5SDavid du Colombier ref empty_array, filter1_array, parms1_array;
523ff48bf5SDavid du Colombier uint i;
533ff48bf5SDavid du Colombier int code;
543ff48bf5SDavid du Colombier
553ff48bf5SDavid du Colombier make_empty_array(&empty_array, a_readonly);
563ff48bf5SDavid du Colombier if (dict_find_string(op, "Filter", &pFilter) > 0) {
573ff48bf5SDavid du Colombier if (!r_is_array(pFilter)) {
583ff48bf5SDavid du Colombier if (!r_has_type(pFilter, t_name))
593ff48bf5SDavid du Colombier return_error(e_typecheck);
603ff48bf5SDavid du Colombier make_array(&filter1_array, a_readonly, 1, pFilter);
613ff48bf5SDavid du Colombier pFilter = &filter1_array;
623ff48bf5SDavid du Colombier }
633ff48bf5SDavid du Colombier } else
643ff48bf5SDavid du Colombier pFilter = &empty_array;
653ff48bf5SDavid du Colombier /* If Filter is undefined, ignore DecodeParms. */
663ff48bf5SDavid du Colombier if (pFilter != &empty_array &&
673ff48bf5SDavid du Colombier dict_find_string(op, "DecodeParms", &pDecodeParms) > 0
683ff48bf5SDavid du Colombier ) {
693ff48bf5SDavid du Colombier if (pFilter == &filter1_array) {
703ff48bf5SDavid du Colombier make_array(&parms1_array, a_readonly, 1, pDecodeParms);
713ff48bf5SDavid du Colombier pDecodeParms = &parms1_array;
723ff48bf5SDavid du Colombier } else if (!r_is_array(pDecodeParms))
733ff48bf5SDavid du Colombier return_error(e_typecheck);
743ff48bf5SDavid du Colombier else if (r_size(pFilter) != r_size(pDecodeParms))
753ff48bf5SDavid du Colombier return_error(e_rangecheck);
763ff48bf5SDavid du Colombier } else
773ff48bf5SDavid du Colombier pDecodeParms = 0;
783ff48bf5SDavid du Colombier for (i = 0; i < r_size(pFilter); ++i) {
793ff48bf5SDavid du Colombier ref f, fname, dp;
803ff48bf5SDavid du Colombier
81*593dc095SDavid du Colombier array_get(imemory, pFilter, (long)i, &f);
823ff48bf5SDavid du Colombier if (!r_has_type(&f, t_name))
833ff48bf5SDavid du Colombier return_error(e_typecheck);
84*593dc095SDavid du Colombier name_string_ref(imemory, &f, &fname);
853ff48bf5SDavid du Colombier if (r_size(&fname) < 6 ||
863ff48bf5SDavid du Colombier memcmp(fname.value.bytes + r_size(&fname) - 6, "Decode", 6)
873ff48bf5SDavid du Colombier )
883ff48bf5SDavid du Colombier return_error(e_rangecheck);
893ff48bf5SDavid du Colombier if (pDecodeParms) {
90*593dc095SDavid du Colombier array_get(imemory, pDecodeParms, (long)i, &dp);
913ff48bf5SDavid du Colombier if (!(r_has_type(&dp, t_dictionary) || r_has_type(&dp, t_null)))
923ff48bf5SDavid du Colombier return_error(e_typecheck);
933ff48bf5SDavid du Colombier }
943ff48bf5SDavid du Colombier }
953ff48bf5SDavid du Colombier if ((code = dict_int_param(op, "Intent", 0, 3, 0, &Intent)) < 0 ||
963ff48bf5SDavid du Colombier (code = dict_bool_param(op, "AsyncRead", false, &AsyncRead)) < 0
973ff48bf5SDavid du Colombier )
983ff48bf5SDavid du Colombier return code;
993ff48bf5SDavid du Colombier push(1);
1003ff48bf5SDavid du Colombier op[-1] = *pFilter;
1013ff48bf5SDavid du Colombier if (pDecodeParms)
1023ff48bf5SDavid du Colombier *op = *pDecodeParms;
1033ff48bf5SDavid du Colombier else
1043ff48bf5SDavid du Colombier make_null(op);
1053ff48bf5SDavid du Colombier return 0;
1063ff48bf5SDavid du Colombier }
1073ff48bf5SDavid du Colombier
1083ff48bf5SDavid du Colombier /* <file|string> <CloseSource> .reusablestream <filter> */
1093ff48bf5SDavid du Colombier /*
1103ff48bf5SDavid du Colombier * The file|string operand must be a "reusable source", either:
1113ff48bf5SDavid du Colombier * - A string or bytestring;
1123ff48bf5SDavid du Colombier * - A readable, positionable file stream;
1133ff48bf5SDavid du Colombier * - A readable string stream;
1143ff48bf5SDavid du Colombier * - A SubFileDecode filter with an empty EODString and a reusable
1153ff48bf5SDavid du Colombier * source.
1163ff48bf5SDavid du Colombier * Reusable streams are also reusable sources, but they look just like
1173ff48bf5SDavid du Colombier * ordinary file or string streams.
1183ff48bf5SDavid du Colombier */
119*593dc095SDavid du Colombier private int make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data,
1203ff48bf5SDavid du Colombier uint size, int space, long offset, long length,
121*593dc095SDavid du Colombier bool is_bytestring);
122*593dc095SDavid du Colombier private int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs,
123*593dc095SDavid du Colombier long offset, long length);
1243ff48bf5SDavid du Colombier private int
zreusablestream(i_ctx_t * i_ctx_p)1253ff48bf5SDavid du Colombier zreusablestream(i_ctx_t *i_ctx_p)
1263ff48bf5SDavid du Colombier {
1273ff48bf5SDavid du Colombier os_ptr op = osp;
1283ff48bf5SDavid du Colombier os_ptr source_op = op - 1;
1293ff48bf5SDavid du Colombier long length = max_long;
1303ff48bf5SDavid du Colombier bool close_source;
1313ff48bf5SDavid du Colombier int code;
1323ff48bf5SDavid du Colombier
1333ff48bf5SDavid du Colombier check_type(*op, t_boolean);
1343ff48bf5SDavid du Colombier close_source = op->value.boolval;
1353ff48bf5SDavid du Colombier if (r_has_type(source_op, t_string)) {
1363ff48bf5SDavid du Colombier uint size = r_size(source_op);
1373ff48bf5SDavid du Colombier
1383ff48bf5SDavid du Colombier check_read(*source_op);
1393ff48bf5SDavid du Colombier code = make_rss(i_ctx_p, source_op, source_op->value.const_bytes,
1403ff48bf5SDavid du Colombier size, r_space(source_op), 0L, size, false);
1413ff48bf5SDavid du Colombier } else if (r_has_type(source_op, t_astruct)) {
1423ff48bf5SDavid du Colombier uint size = gs_object_size(imemory, source_op->value.pstruct);
1433ff48bf5SDavid du Colombier
1443ff48bf5SDavid du Colombier if (gs_object_type(imemory, source_op->value.pstruct) != &st_bytes)
1453ff48bf5SDavid du Colombier return_error(e_rangecheck);
1463ff48bf5SDavid du Colombier check_read(*source_op);
1473ff48bf5SDavid du Colombier code = make_rss(i_ctx_p, source_op,
1483ff48bf5SDavid du Colombier (const byte *)source_op->value.pstruct, size,
1493ff48bf5SDavid du Colombier r_space(source_op), 0L, size, true);
1503ff48bf5SDavid du Colombier } else {
1513ff48bf5SDavid du Colombier long offset = 0;
1523ff48bf5SDavid du Colombier stream *source;
1533ff48bf5SDavid du Colombier stream *s;
1543ff48bf5SDavid du Colombier
1553ff48bf5SDavid du Colombier check_read_file(source, source_op);
1563ff48bf5SDavid du Colombier s = source;
1573ff48bf5SDavid du Colombier rs:
1583ff48bf5SDavid du Colombier if (s->cbuf_string.data != 0) { /* string stream */
1593ff48bf5SDavid du Colombier long pos = stell(s);
1603ff48bf5SDavid du Colombier long avail = sbufavailable(s) + pos;
1613ff48bf5SDavid du Colombier
1623ff48bf5SDavid du Colombier offset += pos;
1633ff48bf5SDavid du Colombier code = make_rss(i_ctx_p, source_op, s->cbuf_string.data,
1643ff48bf5SDavid du Colombier s->cbuf_string.size,
1653ff48bf5SDavid du Colombier imemory_space((const gs_ref_memory_t *)s->memory),
1663ff48bf5SDavid du Colombier offset, min(avail, length), false);
1673ff48bf5SDavid du Colombier } else if (s->file != 0) { /* file stream */
1683ff48bf5SDavid du Colombier if (~s->modes & (s_mode_read | s_mode_seek))
1693ff48bf5SDavid du Colombier return_error(e_ioerror);
1703ff48bf5SDavid du Colombier code = make_rfs(i_ctx_p, source_op, s, offset + stell(s), length);
1713ff48bf5SDavid du Colombier } else if (s->state->template == &s_SFD_template) {
1723ff48bf5SDavid du Colombier /* SubFileDecode filter */
1733ff48bf5SDavid du Colombier const stream_SFD_state *const sfd_state =
1743ff48bf5SDavid du Colombier (const stream_SFD_state *)s->state;
1753ff48bf5SDavid du Colombier
1763ff48bf5SDavid du Colombier if (sfd_state->eod.size != 0)
1773ff48bf5SDavid du Colombier return_error(e_rangecheck);
1783ff48bf5SDavid du Colombier offset += sfd_state->skip_count - sbufavailable(s);
1793ff48bf5SDavid du Colombier if (sfd_state->count != 0) {
1803ff48bf5SDavid du Colombier long left = max(sfd_state->count, 0) + sbufavailable(s);
1813ff48bf5SDavid du Colombier
1823ff48bf5SDavid du Colombier if (left < length)
1833ff48bf5SDavid du Colombier length = left;
1843ff48bf5SDavid du Colombier }
1853ff48bf5SDavid du Colombier s = s->strm;
1863ff48bf5SDavid du Colombier goto rs;
1873ff48bf5SDavid du Colombier }
1883ff48bf5SDavid du Colombier else /* some other kind of stream */
1893ff48bf5SDavid du Colombier return_error(e_rangecheck);
1903ff48bf5SDavid du Colombier if (close_source) {
1913ff48bf5SDavid du Colombier stream *rs = fptr(source_op);
1923ff48bf5SDavid du Colombier
1933ff48bf5SDavid du Colombier rs->strm = source; /* only for close_source */
1943ff48bf5SDavid du Colombier rs->close_strm = true;
1953ff48bf5SDavid du Colombier }
1963ff48bf5SDavid du Colombier }
1973ff48bf5SDavid du Colombier if (code >= 0)
1983ff48bf5SDavid du Colombier pop(1);
1993ff48bf5SDavid du Colombier return code;
2003ff48bf5SDavid du Colombier }
2013ff48bf5SDavid du Colombier
2023ff48bf5SDavid du Colombier /* Make a reusable string stream. */
2033ff48bf5SDavid du Colombier 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)2043ff48bf5SDavid du Colombier make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size,
2053ff48bf5SDavid du Colombier int string_space, long offset, long length, bool is_bytestring)
2063ff48bf5SDavid du Colombier {
2073ff48bf5SDavid du Colombier stream *s;
2083ff48bf5SDavid du Colombier long left = min(length, size - offset);
2093ff48bf5SDavid du Colombier
2103ff48bf5SDavid du Colombier if (icurrent_space < string_space)
2113ff48bf5SDavid du Colombier return_error(e_invalidaccess);
2123ff48bf5SDavid du Colombier s = file_alloc_stream(imemory, "make_rss");
2133ff48bf5SDavid du Colombier if (s == 0)
2143ff48bf5SDavid du Colombier return_error(e_VMerror);
2153ff48bf5SDavid du Colombier sread_string_reusable(s, data + offset, max(left, 0));
2163ff48bf5SDavid du Colombier if (is_bytestring)
2173ff48bf5SDavid du Colombier s->cbuf_string.data = 0; /* byte array, not string */
2183ff48bf5SDavid du Colombier make_stream_file(op, s, "r");
2193ff48bf5SDavid du Colombier return 0;
2203ff48bf5SDavid du Colombier }
2213ff48bf5SDavid du Colombier
2223ff48bf5SDavid du Colombier /* Make a reusable file stream. */
2233ff48bf5SDavid du Colombier private int
make_rfs(i_ctx_t * i_ctx_p,os_ptr op,stream * fs,long offset,long length)2243ff48bf5SDavid du Colombier make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length)
2253ff48bf5SDavid du Colombier {
2263ff48bf5SDavid du Colombier gs_const_string fname;
227*593dc095SDavid du Colombier gs_parsed_file_name_t pname;
2283ff48bf5SDavid du Colombier stream *s;
2293ff48bf5SDavid du Colombier int code;
2303ff48bf5SDavid du Colombier
2313ff48bf5SDavid du Colombier if (sfilename(fs, &fname) < 0)
2323ff48bf5SDavid du Colombier return_error(e_ioerror);
233*593dc095SDavid du Colombier code = gs_parse_file_name(&pname, (const char *)fname.data, fname.size);
234*593dc095SDavid du Colombier if (code < 0)
235*593dc095SDavid du Colombier return code;
236*593dc095SDavid du Colombier if (pname.len == 0) /* %stdin% etc. won't have a filename */
2373ff48bf5SDavid du Colombier return_error(e_invalidfileaccess); /* can't reopen */
238*593dc095SDavid du Colombier if (pname.iodev == NULL)
239*593dc095SDavid du Colombier pname.iodev = iodev_default;
2403ff48bf5SDavid du Colombier /* Open the file again, to be independent of the source. */
241*593dc095SDavid du Colombier code = file_open_stream((const char *)pname.fname, pname.len, "r",
242*593dc095SDavid du Colombier fs->cbsize, &s, pname.iodev,
243*593dc095SDavid du Colombier pname.iodev->procs.fopen, imemory);
2443ff48bf5SDavid du Colombier if (code < 0)
2453ff48bf5SDavid du Colombier return code;
2463ff48bf5SDavid du Colombier if (sread_subfile(s, offset, length) < 0) {
2473ff48bf5SDavid du Colombier sclose(s);
2483ff48bf5SDavid du Colombier return_error(e_ioerror);
2493ff48bf5SDavid du Colombier }
2503ff48bf5SDavid du Colombier s->close_at_eod = false;
2513ff48bf5SDavid du Colombier make_stream_file(op, s, "r");
2523ff48bf5SDavid du Colombier return 0;
2533ff48bf5SDavid du Colombier }
2543ff48bf5SDavid du Colombier
2553ff48bf5SDavid du Colombier /* ---------------- Initialization procedure ---------------- */
2563ff48bf5SDavid du Colombier
2573ff48bf5SDavid du Colombier const op_def zfrsd_op_defs[] =
2583ff48bf5SDavid du Colombier {
2593ff48bf5SDavid du Colombier {"2.reusablestream", zreusablestream},
2603ff48bf5SDavid du Colombier {"2.rsdparams", zrsdparams},
2613ff48bf5SDavid du Colombier op_def_end(0)
2623ff48bf5SDavid du Colombier };
263