[gs-cvs] rev 8810 - in trunk/gs: lib src
alexcher at ghostscript.com
alexcher at ghostscript.com
Sun Jun 29 17:05:41 PDT 2008
Author: alexcher
Date: 2008-06-29 17:05:40 -0700 (Sun, 29 Jun 2008)
New Revision: 8810
Modified:
trunk/gs/lib/gs_frsd.ps
trunk/gs/src/gxshade.c
trunk/gs/src/int.mak
trunk/gs/src/zfrsd.c
Log:
Add one more way to store data of the reusable stream: an array of strings.
Read the input stream into an array of strings during reusable stream
construction and use the array directly as a data storage.
Bug 689476, customer 190.
DIFFERENCES:
None
Modified: trunk/gs/lib/gs_frsd.ps
===================================================================
--- trunk/gs/lib/gs_frsd.ps 2008-06-28 15:42:59 UTC (rev 8809)
+++ trunk/gs/lib/gs_frsd.ps 2008-06-30 00:05:40 UTC (rev 8810)
@@ -31,25 +31,25 @@
% from the RSD dictionary; all the others should have
% CloseSource = true.
% Stack: source dict filters parms
- 2 index /CloseSource .knownget not { false } if 5 -1 roll
+ 2 index /CloseSource .knownget not { //false } if 5 -1 roll
% Stack: dict filters parms CloseSource source
0 1 5 index length 1 sub {
4 index 1 index get
% Stack: dict filters parms CloseSource source index filtname
- 4 index null eq {
+ 4 index //null eq {
0 dict
} {
- 4 index 2 index get dup null eq { pop } if
+ 4 index 2 index get dup //null eq { pop } if
} ifelse
3 -1 roll pop exch filter
- exch pop true exch % set CloseSource for further filters
+ exch pop //true exch % set CloseSource for further filters
} for
% If AsyncRead is true, try to create the filter directly.
% Stack: dict filters parms CloseSource source
- 4 index /AsyncRead .knownget not { false } if {
+ 4 index /AsyncRead .knownget not { //false } if {
1 index { .reusablestream } .internalstopped
} {
- null true
+ //null //true
} ifelse {
pop
% No luck. Read the entire contents of the stream now.
@@ -59,22 +59,16 @@
} if
% We must allocate the string in the same VM space as its
% source, since the reusable stream must be allocated there.
+
.currentglobal 1 index gcheck .setglobal exch
- % Stack: dict filters parms CloseSource oldglobal file
- 10 dict exch {
- % Stack: dict filters parms CloseSource oldglobal contdict file
- dup 64000 string readstring
- 3 index dup length 4 -1 roll put not { exit } if
- } loop pop
- % Concatenate the contents into one big string.
- % Stack: dict filters parms CloseSource oldglobal contdict
- 0 1 index { length exch pop add } forall
- dup 65400 gt { .bytestring } { string } ifelse
- 3 -1 roll .setglobal exch {
- % Stack: dict filters parms CloseSource string index substring
- exch 64000 mul exch 2 index 3 1 roll putinterval
- } forall
- % Now create the stream on the string.
+ currentpacking //false setpacking exch
+ % Stack: dict filters parms CloseSource oldglobal oldpacking file
+ [ exch { dup 40000 string readstring not { exit } if exch } loop
+ exch pop
+ ]
+ % Stack: dict filters parms CloseSource oldglobal oldpacking [()...]
+ 3 1 roll setpacking setglobal
+ % Stack: dict filters parms CloseSource [()...]
1 index .reusablestream
} if
% We created the stream successfully: clean up.
Modified: trunk/gs/src/gxshade.c
===================================================================
--- trunk/gs/src/gxshade.c 2008-06-28 15:42:59 UTC (rev 8809)
+++ trunk/gs/src/gxshade.c 2008-06-30 00:05:40 UTC (rev 8810)
@@ -55,7 +55,7 @@
cs->pctm = &pis->ctm;
if (data_source_is_stream(params->DataSource)) {
/*
- * Reset the data stream iff it is reusable -- either a reusable
+ * Rewind the data stream iff it is reusable -- either a reusable
* file or a reusable string.
*/
stream *s = cs->s = params->DataSource.data.strm;
@@ -63,7 +63,7 @@
if ((s->file != 0 && s->file_limit != max_long) ||
(s->file == 0 && s->strm == 0)
)
- sreset(s);
+ sseek(s, 0);
} else {
s_init(&cs->ds, NULL);
sread_string(&cs->ds, params->DataSource.data.str.data,
Modified: trunk/gs/src/int.mak
===================================================================
--- trunk/gs/src/int.mak 2008-06-28 15:42:59 UTC (rev 8809)
+++ trunk/gs/src/int.mak 2008-06-30 00:05:40 UTC (rev 8810)
@@ -1060,7 +1060,7 @@
$(PSOBJ)zfrsd.$(OBJ) : $(PSSRC)zfrsd.c $(OP) $(memory__h)\
$(gsfname_h) $(gxiodev_h)\
$(sfilter_h) $(stream_h) $(strimpl_h)\
- $(files_h) $(idict_h) $(idparam_h) $(iname_h) $(store_h)
+ $(files_h) $(idict_h) $(idparam_h) $(iname_h) $(istruct_h) $(store_h)
$(PSCC) $(PSO_)zfrsd.$(OBJ) $(C_) $(PSSRC)zfrsd.c
# ======================== PostScript Level 2 ======================== #
Modified: trunk/gs/src/zfrsd.c
===================================================================
--- trunk/gs/src/zfrsd.c 2008-06-28 15:42:59 UTC (rev 8809)
+++ trunk/gs/src/zfrsd.c 2008-06-30 00:05:40 UTC (rev 8810)
@@ -25,6 +25,7 @@
#include "idict.h"
#include "idparam.h"
#include "iname.h"
+#include "istruct.h"
#include "store.h"
/* ---------------- Reusable streams ---------------- */
@@ -108,6 +109,7 @@
/*
* The file|string operand must be a "reusable source", either:
* - A string or bytestring;
+ * - An array of strings;
* - A readable, positionable file stream;
* - A readable string stream;
* - A SubFileDecode filter with an empty EODString and a reusable
@@ -120,6 +122,10 @@
bool is_bytestring);
static int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs,
long offset, long length);
+
+static int make_aos(i_ctx_t *i_ctx_p, os_ptr op,
+ int blk_sz, int blk_sz_last, unsigned int file_sz);
+
static int
zreusablestream(i_ctx_t *i_ctx_p)
{
@@ -146,6 +152,32 @@
code = make_rss(i_ctx_p, source_op,
(const byte *)source_op->value.pstruct, size,
r_space(source_op), 0L, size, true);
+ } else if (r_has_type(source_op, t_array)) { /* no packedarrays */
+ int i, blk_cnt, blk_sz;
+ ref *blk_ref;
+ ulong filelen = 0;
+
+ check_read(*source_op);
+ blk_cnt = r_size(source_op);
+ blk_ref = source_op->value.refs;
+ if (blk_cnt > 0) {
+ blk_sz = r_size(blk_ref);
+ for (i = 0; i < blk_cnt; i++) {
+ int len;
+
+ check_read_type(blk_ref[i], t_string);
+ len = r_size(&blk_ref[i]);
+ if (len > blk_sz || len < blk_sz && i < blk_cnt - 1)
+ return_error(e_rangecheck); /* last block can be smaller */
+ filelen += len;
+ }
+ }
+ if (filelen == 0) {
+ code = make_rss(i_ctx_p, source_op, (unsigned char *)"", 0,
+ r_space(source_op), 0, 0, false);
+ } else {
+ code = make_aos(i_ctx_p, source_op, blk_sz, r_size(&blk_ref[blk_cnt - 1]), filelen);
+ }
} else {
long offset = 0;
stream *source;
@@ -255,7 +287,181 @@
make_stream_file(op, s, "r");
return 0;
}
+/* ----------- Reusable array-of-strings stream ------------- */
+static int s_aos_available(stream *, long *);
+static int s_aos_seek(stream *, long);
+static void s_aos_reset(stream *s);
+static int s_aos_flush(stream *s);
+static int s_aos_close(stream *);
+static int s_aos_process(stream_state *, stream_cursor_read *,
+ stream_cursor_write *, bool);
+
+/* Stream state */
+typedef struct aos_state_s {
+ stream_state_common;
+ ref blocks;
+ stream *s;
+ int blk_sz;
+ int blk_sz_last;
+ uint file_sz;
+} aos_state_t;
+
+/* GC procedures */
+static
+CLEAR_MARKS_PROC(aos_clear_marks)
+{ aos_state_t *const pptr = vptr;
+
+ r_clear_attrs(&pptr->blocks, l_mark);
+}
+static
+ENUM_PTRS_WITH(aos_enum_ptrs, aos_state_t *pptr) return 0;
+ENUM_PTR(0, gs_context_state_t, pgs);
+case 1:
+ENUM_RETURN_REF(&pptr->blocks);
+ENUM_PTRS_END
+static RELOC_PTRS_WITH(aos_reloc_ptrs, aos_state_t *pptr);
+RELOC_PTR(aos_state_t, s);
+RELOC_REF_VAR(pptr->blocks);
+r_clear_attrs(&pptr->blocks, l_mark);
+RELOC_PTRS_END
+
+gs_private_st_complex_only(st_aos_state, aos_state_t,
+ "aos_state", aos_clear_marks, aos_enum_ptrs, aos_reloc_ptrs, 0);
+
+/* Stream template */
+static const stream_template s_aos_template = {
+ &st_aos_state, 0, s_aos_process, 1, 1, 0, 0 };
+
+/* Stream procs */
+static const stream_procs s_aos_procs = {
+ s_aos_available, s_aos_seek, s_aos_reset,
+ s_aos_flush, s_aos_close, s_aos_process,
+ NULL /* no s_aos_switch */
+};
+
+static int
+make_aos(i_ctx_t *i_ctx_p, os_ptr op, int blk_sz, int blk_sz_last, uint file_sz)
+{
+ stream *s;
+ aos_state_t *ss;
+ byte *buf;
+ const int aos_buf_size = 1024; /* arbitrary */
+ uint save_space = icurrent_space;
+ ialloc_set_space(idmemory, r_space(op));
+
+ s = s_alloc(imemory, "aos_stream");
+ ss = (aos_state_t *)s_alloc_state(imemory, &st_aos_state, "st_aos_state");
+ buf = gs_alloc_bytes(imemory, aos_buf_size, "aos_stream_buf");
+ if (s == 0 || ss == 0 || buf == 0) {
+ gs_free_object(imemory, buf, "aos_stream_buf");
+ gs_free_object(imemory, ss, "st_aos_state");
+ gs_free_object(imemory, s, "aos_stream");
+ ialloc_set_space(idmemory, save_space);
+ return_error(e_VMerror);
+ }
+ ialloc_set_space(idmemory, save_space);
+ ss->template = &s_aos_template;
+ ss->blocks = *op;
+ ss->s = s;
+ ss->blk_sz = blk_sz;
+ ss->blk_sz_last = blk_sz_last;
+ ss->file_sz = file_sz;
+ s_std_init(s, buf, aos_buf_size, &s_aos_procs, s_mode_read + s_mode_seek);
+ s->state = (stream_state *)ss;
+ s->file_offset = 0;
+ s->file_limit = max_long;
+ s->close_at_eod = false;
+ make_stream_file(op, s, "r");
+ return 0;
+}
+
+/* Return the number of available bytes */
+static int
+s_aos_available(stream *s, long *pl)
+{
+ *pl = ((aos_state_t *)s->state)->file_sz - stell(s);
+ return 0;
+}
+
+/* Seek in a string being read. Return 0 if OK, ERRC if not. */
+static int
+s_aos_seek(register stream * s, long pos)
+{
+ uint end = s->srlimit - s->cbuf + 1;
+ long offset = pos - s->position;
+
+ if (offset >= 0 && offset <= end) { /* Staying within the same buffer */
+ s->srptr = s->cbuf + offset - 1;
+ return 0;
+ }
+ if (pos < 0 || pos > s->file_limit)
+ return ERRC;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ s->end_status = 0;
+ s->position = pos;
+ return 0;
+}
+
+static void
+s_aos_reset(stream *s)
+{
+ /* PLRM definition of reset operator is strange. */
+ /* Rewind the file and discard the buffer. */
+ s->position = 0;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ s->end_status = 0;
+}
+
+static int
+s_aos_flush(stream *s)
+{
+ s->position = ((aos_state_t *)s->state)->file_sz;
+ s->srptr = s->srlimit = s->cbuf - 1;
+ return 0;
+}
+
+static int
+s_aos_close(stream * s)
+{
+ gs_free_object(s->memory, s->cbuf, "s_aos_close(buffer)");
+ s->cbuf = 0;
+ /* Increment the IDs to prevent further access. */
+ s->read_id = s->write_id = (s->read_id | s->write_id) + 1;
+ return 0;
+}
+
+static int
+s_aos_process(stream_state * st, stream_cursor_read * ignore_pr,
+ stream_cursor_write * pw, bool last)
+{
+ int blk_i, blk_off, blk_cnt, status = 1;
+ uint count;
+ aos_state_t *ss = (aos_state_t *)st;
+ uint max_count = pw->limit - pw->ptr;
+ uint pos = stell(ss->s);
+ unsigned const char *data;
+ ref *blk_ref;
+
+ if (pos >= ss->file_sz)
+ return EOFC;
+ blk_i = pos / ss->blk_sz;
+ blk_off = pos % ss->blk_sz;
+ blk_cnt = r_size(&ss->blocks);
+ count = blk_i < blk_cnt - 1 ? ss->blk_sz : ss->blk_sz_last;
+ blk_ref = ss->blocks.value.refs;
+ data = blk_ref[blk_i].value.bytes;
+
+ if (max_count > count - blk_off) {
+ max_count = count - blk_off;
+ if (blk_i == blk_cnt - 1)
+ status = EOFC;
+ }
+ memcpy(pw->ptr+1, data + blk_off, max_count);
+ pw->ptr += max_count;
+ return status;
+}
+
/* ---------------- Initialization procedure ---------------- */
const op_def zfrsd_op_defs[] =
More information about the gs-cvs
mailing list