xref: /plan9-contrib/sys/src/cmd/gs/src/zfrsd.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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