/* * Create an Indexed color space. This is a single-use procedure, * broken out only for readability. */ static int pdf_indexed_color_space(gx_device_pdf *pdev, cos_value_t *pvalue, const gs_color_space *pcs, cos_array_t *pca) { const gs_indexed_params *pip = &pcs->params.indexed; const gs_color_space *base_space = pcs->base_space; int num_entries = pip->hival + 1; int num_components = gs_color_space_num_components(base_space); uint table_size = num_entries * num_components; /* Guess at the extra space needed for PS string encoding. */ uint string_size = 2 + table_size * 4; uint string_used; byte buf[100]; /* arbitrary */ stream_AXE_state st; stream s, es; gs_memory_t *mem = pdev->pdf_memory; byte *table; byte *palette; cos_value_t v; int code; /* PDF doesn't support Indexed color spaces with more than 256 entries. */ if (num_entries > 256) return_error(gs_error_rangecheck); if (pdev->CompatibilityLevel < 1.3) { switch (gs_color_space_get_index(pcs)) { case gs_color_space_index_Pattern: case gs_color_space_index_Separation: case gs_color_space_index_Indexed: case gs_color_space_index_DeviceN: return_error(gs_error_rangecheck); default: DO_NOTHING; } } table = gs_alloc_string(mem, string_size, "pdf_color_space(table)"); palette = gs_alloc_string(mem, table_size, "pdf_color_space(palette)"); if (table == 0 || palette == 0) { gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); gs_free_string(mem, table, string_size, "pdf_color_space(table)"); return_error(gs_error_VMerror); } s_init(&s, mem); swrite_string(&s, table, string_size); s_init(&es, mem); s_init_state((stream_state *)&st, &s_PSSE_template, NULL); s_init_filter(&es, (stream_state *)&st, buf, sizeof(buf), &s); sputc(&s, '('); if (pcs->params.indexed.use_proc) { gs_client_color cmin, cmax; byte *pnext = palette; int i, j; /* Find the legal range for the color components. */ for (j = 0; j < num_components; ++j) cmin.paint.values[j] = (float)min_long, cmax.paint.values[j] = (float)max_long; gs_color_space_restrict_color(&cmin, base_space); gs_color_space_restrict_color(&cmax, base_space); /* * Compute the palette values, with the legal range for each * one mapped to [0 .. 255]. */ for (i = 0; i < num_entries; ++i) { gs_client_color cc; gs_cspace_indexed_lookup(pcs, i, &cc); for (j = 0; j < num_components; ++j) { float v = (cc.paint.values[j] - cmin.paint.values[j]) * 255 / (cmax.paint.values[j] - cmin.paint.values[j]); *pnext++ = (v <= 0 ? 0 : v >= 255 ? 255 : (byte)v); } } } else memcpy(palette, pip->lookup.table.data, table_size); if (gs_color_space_get_index(base_space) == gs_color_space_index_DeviceRGB ) { /* Check for an all-gray palette3. */ int i; for (i = table_size; (i -= 3) >= 0; ) if (palette[i] != palette[i + 1] || palette[i] != palette[i + 2] ) break; if (i < 0) { /* Change the color space to DeviceGray. */ for (i = 0; i < num_entries; ++i) palette[i] = palette[i * 3]; table_size = num_entries; base_space = gs_cspace_new_DeviceGray(mem); } } stream_write(&es, palette, table_size); gs_free_string(mem, palette, table_size, "pdf_color_space(palette)"); sclose(&es); sflush(&s); string_used = (uint)stell(&s); table = gs_resize_string(mem, table, string_size, string_used, "pdf_color_space(table)"); /* * Since the array is always referenced by name as a resource * rather than being written as a value, even for in-line images, * always use the full name for the color space. * * We don't have to worry about the range of the base space: * in PDF, unlike PostScript, the values from the lookup table are * scaled automatically. */ if ((code = pdf_color_space(pdev, pvalue, NULL, base_space, &pdf_color_space_names, false)) < 0 || (code = cos_array_add(pca, cos_c_string_value(&v, pdf_color_space_names.Indexed /*pcsn->Indexed*/))) < 0 || (code = cos_array_add(pca, pvalue)) < 0 || (code = cos_array_add_int(pca, pip->hival)) < 0 || (code = cos_array_add_no_copy(pca, cos_string_value(&v, table, string_used))) < 0 ) return code; return 0; }
int gs_image_next_planes(gs_image_enum * penum, gs_const_string *plane_data /*[num_planes]*/, uint *used /*[num_planes]*/) { const int num_planes = penum->num_planes; int i; int code = 0; #ifdef DEBUG vd_get_dc('i'); vd_set_shift(0, 0); vd_set_scale(0.01); vd_set_origin(0, 0); if (gs_debug_c('b')) { int pi; for (pi = 0; pi < num_planes; ++pi) dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n", pi, (ulong)penum->planes[pi].source.data, penum->planes[pi].source.size, penum->planes[pi].pos, (ulong)plane_data[pi].data, plane_data[pi].size); } #endif for (i = 0; i < num_planes; ++i) { used[i] = 0; if (penum->wanted[i] && plane_data[i].size != 0) { penum->planes[i].source.size = plane_data[i].size; penum->planes[i].source.data = plane_data[i].data; } } for (;;) { /* If wanted can vary, only transfer 1 row at a time. */ int h = (penum->wanted_varies ? 1 : max_int); /* Move partial rows from source[] to row[]. */ for (i = 0; i < num_planes; ++i) { int pos, size; uint raster; if (!penum->wanted[i]) continue; /* skip unwanted planes */ pos = penum->planes[i].pos; size = penum->planes[i].source.size; raster = penum->image_planes[i].raster; if (size > 0) { if (pos < raster && (pos != 0 || size < raster)) { /* Buffer a partial row. */ int copy = min(size, raster - pos); uint old_size = penum->planes[i].row.size; /* Make sure the row buffer is fully allocated. */ if (raster > old_size) { gs_memory_t *mem = gs_image_row_memory(penum); byte *old_data = penum->planes[i].row.data; byte *row = (old_data == 0 ? gs_alloc_string(mem, raster, "gs_image_next(row)") : gs_resize_string(mem, old_data, old_size, raster, "gs_image_next(row)")); if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n", i, (ulong)old_data, old_size, (ulong)row, raster); if (row == 0) { code = gs_note_error(gs_error_VMerror); free_row_buffers(penum, i, "gs_image_next(row)"); break; } penum->planes[i].row.data = row; penum->planes[i].row.size = raster; } memcpy(penum->planes[i].row.data + pos, penum->planes[i].source.data, copy); penum->planes[i].source.data += copy; penum->planes[i].source.size = size -= copy; penum->planes[i].pos = pos += copy; used[i] += copy; } } if (h == 0) continue; /* can't transfer any data this cycle */ if (pos == raster) { /* * This plane will be transferred from the row buffer, * so we can only transfer one row. */ h = min(h, 1); penum->image_planes[i].data = penum->planes[i].row.data; } else if (pos == 0 && size >= raster) { /* We can transfer 1 or more planes from the source. */ h = min(h, size / raster); penum->image_planes[i].data = penum->planes[i].source.data; } else h = 0; /* not enough data in this plane */ } if (h == 0 || code != 0) break; /* Pass rows to the device. */ if (penum->dev == 0) { /* * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3 * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT * ****** MAY DIFFER (BY AN INTEGER FACTOR). ALSO, plane_depths[0] * ****** AND plane_widths[0] ARE NOT UPDATED. */ if (penum->y + h < penum->height) code = 0; else h = penum->height - penum->y, code = 1; } else { code = gx_image_plane_data_rows(penum->info, penum->image_planes, h, &h); if_debug2('b', "[b]used %d, code=%d\n", h, code); penum->error = code < 0; } penum->y += h; /* Update positions and sizes. */ if (h == 0) break; for (i = 0; i < num_planes; ++i) { int count; if (!penum->wanted[i]) continue; count = penum->image_planes[i].raster * h; if (penum->planes[i].pos) { /* We transferred the row from the row buffer. */ penum->planes[i].pos = 0; } else { /* We transferred the row(s) from the source. */ penum->planes[i].source.data += count; penum->planes[i].source.size -= count; used[i] += count; } } cache_planes(penum); if (code > 0) break; } /* Return the retained data pointers. */ for (i = 0; i < num_planes; ++i) plane_data[i] = penum->planes[i].source; vd_release_dc; return code; }
/* This opens %statementedit% or %lineedit% and is also the * continuation proc for callouts. * Input: * string is the statement/line buffer, * int is the write index into string * bool is true if %statementedit% * file is stdin * Output: * file is a string based stream * We store the line being read in a PostScript string. * This limits the size to max_string_size (64k). * This could be increased by storing the input line in something * other than a PostScript string. */ int zfilelineedit(i_ctx_t *i_ctx_p) { uint count = 0; bool in_eol = false; int code; os_ptr op = osp; bool statement; stream *s; stream *ins; gs_string str; uint initial_buf_size; const char *filename; /* * buf exists only for stylistic parallelism: all occurrences of * buf-> could just as well be str. . */ gs_string *const buf = &str; check_type(*op, t_string); /* line assembled so far */ buf->data = op->value.bytes; buf->size = op->tas.rsize; check_type(*(op-1), t_integer); /* index */ count = (op-1)->value.intval; check_type(*(op-2), t_boolean); /* statementedit/lineedit */ statement = (op-2)->value.boolval; check_read_file(ins, op - 3); /* %stdin */ /* extend string */ initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE; if (initial_buf_size > max_string_size) return_error(e_limitcheck); if (!buf->data || (buf->size < initial_buf_size)) { count = 0; buf->data = gs_alloc_string(imemory_system, initial_buf_size, "zfilelineedit(buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size = initial_buf_size; } rd: code = zreadline_from(ins, buf, imemory_system, &count, &in_eol); if (buf->size > max_string_size) { /* zreadline_from reallocated the buffer larger than * is valid for a PostScript string. * Return an error, but first realloc the buffer * back to a legal size. */ byte *nbuf = gs_resize_string(imemory_system, buf->data, buf->size, max_string_size, "zfilelineedit(shrink buffer)"); if (nbuf == 0) return_error(e_VMerror); op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = max_string_size; return_error(e_limitcheck); } op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */ op->tas.rsize = buf->size; switch (code) { case EOFC: code = gs_note_error(e_undefinedfilename); /* falls through */ case 0: break; default: code = gs_note_error(e_ioerror); break; case CALLC: { ref rfile; (op-1)->value.intval = count; /* callout is for stdin */ make_file(&rfile, a_readonly | avm_system, ins->read_id, ins); code = s_handle_read_exception(i_ctx_p, code, &rfile, NULL, 0, zfilelineedit); } break; case 1: /* filled buffer */ { uint nsize = buf->size; byte *nbuf; if (nsize >= max_string_size) { code = gs_note_error(e_limitcheck); break; } else if (nsize >= max_string_size / 2) nsize= max_string_size; else nsize = buf->size * 2; nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); break; } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; goto rd; } } if (code != 0) return code; if (statement) { /* If we don't have a complete token, keep going. */ stream st; stream *ts = &st; scanner_state state; ref ignore_value; uint depth = ref_stack_count(&o_stack); int code; /* Add a terminating EOL. */ if (count + 1 > buf->size) { uint nsize; byte *nbuf; nsize = buf->size + 1; if (nsize > max_string_size) { return_error(gs_note_error(e_limitcheck)); } else { nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); return_error(code); } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; } } buf->data[count++] = char_EOL; s_init(ts, NULL); sread_string(ts, buf->data, count); sc: scanner_init_stream_options(&state, ts, SCAN_CHECK_ONLY); code = scan_token(i_ctx_p, &ignore_value, &state); ref_stack_pop_to(&o_stack, depth); if (code < 0) code = scan_EOF; /* stop on scanner error */ switch (code) { case 0: /* read a token */ case scan_BOS: goto sc; /* keep going until we run out of data */ case scan_Refill: goto rd; case scan_EOF: break; default: /* error */ return code; } } buf->data = gs_resize_string(imemory_system, buf->data, buf->size, count, "zfilelineedit(resize buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size; s = file_alloc_stream(imemory_system, "zfilelineedit(stream)"); if (s == 0) return_error(e_VMerror); sread_string(s, buf->data, count); s->save_close = s->procs.close; s->procs.close = file_close_disable; filename = statement ? gs_iodev_statementedit.dname : gs_iodev_lineedit.dname; code = ssetfilename(s, (const byte *)filename, strlen(filename)+1); if (code < 0) { sclose(s); return_error(e_VMerror); } pop(3); make_stream_file(osp, s, "r"); return code; }