/* Copyright (C) 1998, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: zfrsd.c,v 1.4.6.1.2.1 2003/01/17 00:49:06 giles Exp $ */ /* ReusableStreamDecode filter support */ #include "memory_.h" #include "ghost.h" #include "gxiodev.h" #include "oper.h" #include "stream.h" #include "strimpl.h" #include "sfilter.h" /* for SubFileDecode */ #include "files.h" #include "idict.h" #include "idparam.h" #include "iname.h" #include "store.h" /* ---------------- Reusable streams ---------------- */ /* * The actual work of constructing the filter is done in PostScript code. * The operators in this file are internal ones that handle the dirty work. */ /* .rsdparams */ /* filters is always an array; decodeparms is always either an array */ /* of the same length as filters, or null. */ private int zrsdparams(i_ctx_t *i_ctx_p) { os_ptr op = osp; ref *pFilter; ref *pDecodeParms; int Intent; bool AsyncRead; ref empty_array, filter1_array, parms1_array; uint i; int code; make_empty_array(&empty_array, a_readonly); if (dict_find_string(op, "Filter", &pFilter) > 0) { if (!r_is_array(pFilter)) { if (!r_has_type(pFilter, t_name)) return_error(e_typecheck); make_array(&filter1_array, a_readonly, 1, pFilter); pFilter = &filter1_array; } } else pFilter = &empty_array; /* If Filter is undefined, ignore DecodeParms. */ if (pFilter != &empty_array && dict_find_string(op, "DecodeParms", &pDecodeParms) > 0 ) { if (pFilter == &filter1_array) { make_array(&parms1_array, a_readonly, 1, pDecodeParms); pDecodeParms = &parms1_array; } else if (!r_is_array(pDecodeParms)) return_error(e_typecheck); else if (r_size(pFilter) != r_size(pDecodeParms)) return_error(e_rangecheck); } else pDecodeParms = 0; for (i = 0; i < r_size(pFilter); ++i) { ref f, fname, dp; array_get(pFilter, (long)i, &f); if (!r_has_type(&f, t_name)) return_error(e_typecheck); name_string_ref(&f, &fname); if (r_size(&fname) < 6 || memcmp(fname.value.bytes + r_size(&fname) - 6, "Decode", 6) ) return_error(e_rangecheck); if (pDecodeParms) { array_get(pDecodeParms, (long)i, &dp); if (!(r_has_type(&dp, t_dictionary) || r_has_type(&dp, t_null))) return_error(e_typecheck); } } if ((code = dict_int_param(op, "Intent", 0, 3, 0, &Intent)) < 0 || (code = dict_bool_param(op, "AsyncRead", false, &AsyncRead)) < 0 ) return code; push(1); op[-1] = *pFilter; if (pDecodeParms) *op = *pDecodeParms; else make_null(op); return 0; } /* .reusablestream */ /* * The file|string operand must be a "reusable source", either: * - A string or bytestring; * - A readable, positionable file stream; * - A readable string stream; * - A SubFileDecode filter with an empty EODString and a reusable * source. * Reusable streams are also reusable sources, but they look just like * ordinary file or string streams. */ private int make_rss(P8(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size, int space, long offset, long length, bool is_bytestring)); private int make_rfs(P5(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length)); private int zreusablestream(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr source_op = op - 1; long length = max_long; bool close_source; int code; check_type(*op, t_boolean); close_source = op->value.boolval; if (r_has_type(source_op, t_string)) { uint size = r_size(source_op); check_read(*source_op); code = make_rss(i_ctx_p, source_op, source_op->value.const_bytes, size, r_space(source_op), 0L, size, false); } else if (r_has_type(source_op, t_astruct)) { uint size = gs_object_size(imemory, source_op->value.pstruct); if (gs_object_type(imemory, source_op->value.pstruct) != &st_bytes) return_error(e_rangecheck); check_read(*source_op); code = make_rss(i_ctx_p, source_op, (const byte *)source_op->value.pstruct, size, r_space(source_op), 0L, size, true); } else { long offset = 0; stream *source; stream *s; check_read_file(source, source_op); s = source; rs: if (s->cbuf_string.data != 0) { /* string stream */ long pos = stell(s); long avail = sbufavailable(s) + pos; offset += pos; code = make_rss(i_ctx_p, source_op, s->cbuf_string.data, s->cbuf_string.size, imemory_space((const gs_ref_memory_t *)s->memory), offset, min(avail, length), false); } else if (s->file != 0) { /* file stream */ if (~s->modes & (s_mode_read | s_mode_seek)) return_error(e_ioerror); code = make_rfs(i_ctx_p, source_op, s, offset + stell(s), length); } else if (s->state->template == &s_SFD_template) { /* SubFileDecode filter */ const stream_SFD_state *const sfd_state = (const stream_SFD_state *)s->state; if (sfd_state->eod.size != 0) return_error(e_rangecheck); offset += sfd_state->skip_count - sbufavailable(s); if (sfd_state->count != 0) { long left = max(sfd_state->count, 0) + sbufavailable(s); if (left < length) length = left; } s = s->strm; goto rs; } else /* some other kind of stream */ return_error(e_rangecheck); if (close_source) { stream *rs = fptr(source_op); rs->strm = source; /* only for close_source */ rs->close_strm = true; } } if (code >= 0) pop(1); return code; } /* Make a reusable string stream. */ 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) { stream *s; long left = min(length, size - offset); if (icurrent_space < string_space) return_error(e_invalidaccess); s = file_alloc_stream(imemory, "make_rss"); if (s == 0) return_error(e_VMerror); sread_string_reusable(s, data + offset, max(left, 0)); if (is_bytestring) s->cbuf_string.data = 0; /* byte array, not string */ make_stream_file(op, s, "r"); return 0; } /* Make a reusable file stream. */ private int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length) { gs_const_string fname; stream *s; int code; if (sfilename(fs, &fname) < 0) return_error(e_ioerror); if (fname.data[0] == '%') return_error(e_invalidfileaccess); /* can't reopen */ /* Open the file again, to be independent of the source. */ code = file_open_stream((const char *)fname.data, fname.size, "r", fs->cbsize, &s, iodev_default->procs.fopen, imemory); if (code < 0) return code; if (sread_subfile(s, offset, length) < 0) { sclose(s); return_error(e_ioerror); } s->close_at_eod = false; make_stream_file(op, s, "r"); return 0; } /* ---------------- Initialization procedure ---------------- */ const op_def zfrsd_op_defs[] = { {"2.reusablestream", zreusablestream}, {"2.rsdparams", zrsdparams}, op_def_end(0) };