/* Procedures for reading from a file */ static int s_fileno_available(register stream * s, long *pl) { long max_avail = s->file_limit - stell(s); long buf_avail = sbufavailable(s); int fd = sfileno(s); *pl = min(max_avail, buf_avail); if (sseekable(s)) { long pos, end; pos = ltell(fd); if (pos < 0) return ERRC; end = lseek(fd, 0L, SEEK_END); if (lseek(fd, pos, SEEK_SET) < 0 || end < 0) return ERRC; buf_avail += end - pos; *pl = min(max_avail, buf_avail); if (*pl == 0) *pl = -1; /* EOF */ } else { if (*pl == 0) *pl = -1; /* EOF */ } return 0; }
/* <file> <string> .peekstring <substring> <filled_bool> */ static int zpeekstring(i_ctx_t *i_ctx_p) { os_ptr op = osp; stream *s; uint len, rlen; check_read_file(s, op - 1); check_write_type(*op, t_string); len = r_size(op); while ((rlen = sbufavailable(s)) < len) { int status = s->end_status; switch (status) { case EOFC: break; case 0: /* * The following is a HACK. It should reallocate the buffer to hold * at least len bytes. However, this raises messy problems about * which allocator to use and how it should interact with restore. */ if (len >= s->bsize) return_error(e_rangecheck); s_process_read_buf(s); continue; default: return handle_read_status(i_ctx_p, status, op - 1, NULL, zpeekstring); } break; } if (rlen > len) rlen = len; /* Don't remove the data from the buffer. */ memcpy(op->value.bytes, sbufptr(s), rlen); r_set_size(op, rlen); op[-1] = *op; make_bool(op, (rlen == len ? 1 : 0)); return 0; }
static 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 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; stream *s; check_read_file(i_ctx_p, 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->templat == &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; }
/* Continue processing data from an image with file data sources. */ static int image_file_continue(i_ctx_t *i_ctx_p) { gs_image_enum *penum = r_ptr(esp, gs_image_enum); int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; for (;;) { uint min_avail = max_int; gs_const_string plane_data[gs_image_max_planes]; int code; int px; const ref *pp; bool at_eof = false; /* * Do a first pass through the files to ensure that at least * one has data available in its buffer. */ for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources; ++px, pp -= 2 ) { int num_aliases = pp[1].value.intval; stream *s = pp->value.pfile; int min_left; uint avail; if (num_aliases <= 0) num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval; while ((avail = sbufavailable(s)) <= (min_left = sbuf_min_left(s)) + num_aliases - 1) { int next = s->end_status; switch (next) { case 0: s_process_read_buf(s); continue; case EOFC: at_eof = true; break; /* with no data available */ case INTC: case CALLC: return s_handle_read_exception(i_ctx_p, next, pp, NULL, 0, image_file_continue); default: /* case ERRC: */ return_error(e_ioerror); } break; /* for EOFC */ } /* * Note that in the EOF case, we can get here with no data * available. */ if (avail >= min_left) avail = (avail - min_left) / num_aliases; /* may be 0 */ if (avail < min_avail) min_avail = avail; plane_data[px].data = sbufptr(s); plane_data[px].size = avail; } /* * Now pass the available buffered data to the image processor. * Even if there is no available data, we must call * gs_image_next_planes one more time to finish processing any * retained data. */ { int pi; uint used[gs_image_max_planes]; code = gs_image_next_planes(penum, plane_data, used); /* Now that used has been set, update the streams. */ for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources; ++pi, pp -= 2 ) sbufskip(pp->value.pfile, used[pi]); if (code == e_RemapColor) return code; } if (at_eof) code = 1; if (code) { int code1; esp = zimage_pop_estack(esp); code1 = image_cleanup(i_ctx_p); return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack); } } }
/* <source> <dict> eexecDecode/filter <file> */ static int zexD(i_ctx_t *i_ctx_p) { os_ptr op = osp; stream_exD_state state; int code; (*s_exD_template.set_defaults)((stream_state *)&state); if (r_has_type(op, t_dictionary)) { uint cstate; bool is_eexec; check_dict_read(*op); if ((code = dict_uint_param(op, "seed", 0, 0xffff, 0x10000, &cstate)) < 0 || (code = dict_int_param(op, "lenIV", 0, max_int, 4, &state.lenIV)) < 0 || (code = dict_bool_param(op, "eexec", false, &is_eexec)) < 0 || (code = dict_bool_param(op, "keep_spaces", false, &state.keep_spaces)) < 0 ) return code; state.cstate = cstate; state.binary = (is_eexec ? -1 : 1); code = 1; } else { state.binary = 1; code = eexec_param(op, &state.cstate); } if (code < 0) return code; /* * If we're reading a .PFB file, let the filter know about it, * so it can read recklessly to the end of the binary section. */ if (r_has_type(op - 1, t_file)) { stream *s = (op - 1)->value.pfile; if (s->state != 0 && s->state->templat == &s_PFBD_template) { stream_PFBD_state *pss = (stream_PFBD_state *)s->state; state.pfb_state = pss; /* * If we're reading the binary section of a PFB stream, * avoid the conversion from binary to hex and back again. */ if (pss->record_type == 2) { /* * The PFB decoder may have converted some data to hex * already. Convert it back if necessary. */ if (pss->binary_to_hex && sbufavailable(s) > 0) { state.binary = 0; /* start as hex */ state.hex_left = sbufavailable(s); } else { state.binary = 1; } pss->binary_to_hex = 0; } } } return filter_read(i_ctx_p, code, &s_exD_template, (stream_state *)&state, 0); }