/* Close the device */ static int svg_close_device(gx_device *dev) { gx_device_svg *const svg = (gx_device_svg*)dev; svg_write(svg, "\n<!-- svg_close_device -->\n"); /* close any open group elements */ while (svg->mark > 0) { svg_write(svg, "</g>\n"); svg->mark--; } if (svg->header) { svg_write(svg, "</svg>\n"); svg->header = 0; } if (svg->fillcolor) gs_free_string(svg->memory, (byte *)svg->fillcolor, 8, "svg_close_device"); if (svg->strokecolor) gs_free_string(svg->memory, (byte *)svg->strokecolor, 8, "svg_close_device"); if (ferror(svg->file)) return gs_throw_code(gs_error_ioerror); return gdev_vector_close_file((gx_device_vector*)dev); }
static int svg_setstrokecolor(gx_device_vector *vdev, const gs_imager_state *pis, const gx_drawing_color *pdc) { gx_device_svg *svg = (gx_device_svg*)vdev; char *stroke; dprintf("svg_setstrokecolor\n"); stroke = svg_make_color(svg, pdc); if (!stroke) return gs_rethrow_code(gs_error_VMerror); if (svg->strokecolor && !strcmp(stroke, svg->strokecolor)) return 0; /* not a new color */ /* update our state with the new color */ if (svg->strokecolor) gs_free_string(svg->memory, (byte *)svg->strokecolor, 8, "svg_setstrokecolor"); svg->strokecolor = stroke; /* request a new group element */ svg->dirty++; return 0; }
int pdf_font_descriptor_free(gx_device_pdf *pdev, pdf_resource_t *pres) { pdf_font_descriptor_t *pfd = (pdf_font_descriptor_t *)pres; pdf_base_font_t *pbfont = pfd->base_font; gs_font *copied = (gs_font *)pbfont->copied, *complete = (gs_font *)pbfont->complete; gs_free_copied_font(copied); if (complete && copied != complete) { gs_free_copied_font(complete); pbfont->complete = 0; } pbfont->copied = 0; if (pbfont && pbfont->font_name.size) { gs_free_string(pdev->pdf_memory, pbfont->font_name.data, pbfont->font_name.size, "Free BaseFont FontName string"); pbfont->font_name.data = (byte *)0L; pbfont->font_name.size = 0; } if (pbfont) { gs_free_object(cos_object_memory(pres->object), pbfont, "Free base font from FontDescriptor)"); pfd->base_font = 0; } if (pres->object) { gs_free_object(cos_object_memory(pres->object), pres->object, "free FontDescriptor object"); pres->object = NULL; } return 0; }
/* * make a new dictionary entry. */ static int pl_dict_build_new_entry(pl_dict_t * pdict, const byte * kdata, uint ksize, void *value, pl_dict_entry_t * link) { /* Make a new entry. */ byte *kstr; gs_memory_t *mem = pdict->memory; pl_dict_entry_t *pde; pde = gs_alloc_struct(mem, pl_dict_entry_t, &st_pl_dict_entry, "pl_dict_put(entry)"); kstr = (ksize <= pl_dict_max_short_key ? pde->short_key : gs_alloc_string(mem, ksize, "pl_dict_put(key)")); if (pde == 0 || kstr == 0) { if (kstr && kstr != pde->short_key) gs_free_string(mem, kstr, ksize, "pl_dict_put(key)"); gs_free_object(mem, pde, "pl_dict_put(entry)"); return -1; } memcpy(kstr, kdata, ksize); pde->key.data = (ksize <= pl_dict_max_short_key ? 0 : kstr); pde->key.size = ksize; pde->link = link; pde->value = value; pde->next = pdict->entries; pdict->entries = pde; pdict->entry_count++; return 0; }
static void px_gstate_client_free(void *old, gs_memory_t *mem) { px_gstate_t *pxgs = old; px_dict_release(&pxgs->temp_pattern_dict); if ( pxgs->halftone.thresholds.data ) gs_free_string(mem, (byte *)pxgs->halftone.thresholds.data, pxgs->halftone.thresholds.size, "px_gstate_free(halftone.thresholds)"); if ( pxgs->dither_matrix.data ) gs_free_string(mem, (byte *)pxgs->dither_matrix.data, pxgs->dither_matrix.size, "px_gstate_free(dither_matrix)"); px_gstate_rc_adjust(old, -1, mem); gs_free_object(mem, old, "px_gstate_free"); }
/* Delete a dictionary entry. */ static void pl_dict_free(pl_dict_t * pdict, pl_dict_entry_t ** ppde, client_name_t cname) { pl_dict_entry_t *pde = *ppde; gs_memory_t *mem = pdict->memory; *ppde = pde->next; if (!pde->link) /* values are not freed for links */ (*pdict->free_proc) (mem, pde->value, cname); if (pde->key.size > pl_dict_max_short_key) gs_free_string(mem, (byte *) pde->key.data, pde->key.size, cname); gs_free_object(mem, pde, cname); pdict->entry_count--; }
/* Free the row buffers when cleaning up. */ static void free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname) { int i; for (i = num_planes - 1; i >= 0; --i) { if_debug3('b', "[b]free plane %d row (0x%lx,%u)\n", i, (ulong)penum->planes[i].row.data, penum->planes[i].row.size); gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data, penum->planes[i].row.size, cname); penum->planes[i].row.data = 0; penum->planes[i].row.size = 0; } }
static char * svg_make_color(gx_device_svg *svg, const gx_drawing_color *pdc) { char *paint = (char *)gs_alloc_string(svg->memory, 8, "svg_make_color"); if (!paint) { gs_throw(gs_error_VMerror, "string allocation failed"); return NULL; } if (gx_dc_is_pure(pdc)) { gx_color_index color = gx_dc_pure_color(pdc); sprintf(paint, "#%06x", (int)(color & 0xffffffL)); } else if (gx_dc_is_null(pdc)) { sprintf(paint, "None"); } else { gs_free_string(svg->memory, (byte *)paint, 8, "svg_make_color"); gs_throw(gs_error_rangecheck, "unknown color type"); return NULL; } return paint; }
int pxPopGS(px_args_t *par, px_state_t *pxs) { gs_state *pgs = pxs->pgs; px_gstate_t *pxgs = pxs->pxgs; int code; /* * Even though the H-P documentation says that a PopGS with an * empty stack is illegal, the implementations apparently simply * do nothing in this case. */ if ( pxgs->stack_depth == 0 ) return 0; if ( pxgs->palette.data && !pxgs->palette_is_shared ) { gs_free_string(pxs->memory, (byte *)pxgs->palette.data, pxgs->palette.size, "pxPopGS(palette)"); pxgs->palette.data = 0; } px_purge_pattern_cache(pxs, eTempPattern); code = gs_grestore(pgs); pxs->pxgs = gs_state_client_data(pgs); return code; }
/* Get bytes from GlyphData or DataSource. */ static int cid0_read_bytes(gs_font_cid0 *pfont, ulong base, uint count, byte *buf, gs_glyph_data_t *pgd) { const font_data *pfdata = pfont_data(pfont); byte *data = buf; gs_font *gdfont = 0; /* pfont if newly allocated, 0 if not */ int code = 0; /* Check for overflow. */ if (base != (long)base || base > base + count) return_error(e_rangecheck); if (r_has_type(&pfdata->u.cid0.DataSource, t_null)) { /* Get the bytes from GlyphData (a string or array of strings). */ const ref *pgdata = &pfdata->u.cid0.GlyphData; if (r_has_type(pgdata, t_string)) { /* single string */ uint size = r_size(pgdata); if (base >= size || count > size - base) return_error(e_rangecheck); data = pgdata->value.bytes + base; } else { /* array of strings */ /* * The algorithm is similar to the one in * string_array_access_proc in zfont42.c, but it also has to * deal with the case where the requested string crosses array * elements. */ ulong skip = base; uint copied = 0; uint index = 0; ref rstr; uint size; for (;; skip -= size, ++index) { int code = array_get(pfont->memory, pgdata, index, &rstr); if (code < 0) return code; if (!r_has_type(&rstr, t_string)) return_error(e_typecheck); size = r_size(&rstr); if (skip < size) break; } size -= skip; if (count <= size) { data = rstr.value.bytes + skip; } else { /* multiple strings needed */ if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); gdfont = (gs_font *)pfont; /* newly allocated */ } memcpy(data, rstr.value.bytes + skip, size); copied = size; while (copied < count) { int code = array_get(pfont->memory, pgdata, ++index, &rstr); if (code < 0) goto err; if (!r_has_type(&rstr, t_string)) { code = gs_note_error(e_typecheck); goto err; } size = r_size(&rstr); if (size > count - copied) size = count - copied; memcpy(data + copied, rstr.value.bytes, size); copied += size; } } } } else { /* Get the bytes from DataSource (a stream). */ stream *s; uint nread; i_ctx_t *i_ctx_p = get_minst_from_memory(pfont->memory)->i_ctx_p; check_read_known_file(i_ctx_p, s, &pfdata->u.cid0.DataSource, return_error); if (sseek(s, base) < 0) return_error(e_ioerror); if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); gdfont = (gs_font *)pfont; /* newly allocated */ } if (sgets(s, data, count, &nread) < 0 || nread != count) { code = gs_note_error(e_ioerror); goto err; } } gs_glyph_data_from_string(pgd, data, count, gdfont); return code; err: if (data != buf) gs_free_string(pfont->memory, data, count, "cid0_read_bytes"); return code; }
/* * 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; }
/* * Caller should make sure that this device supports saved_pages: * dev_proc(dev, dev_spec_op)(dev, gxdso_supports_saved_pages, NULL, 0) == 1 * * Returns < 0 if error, 1 if erasepage needed, 0 if no action needed. */ int gx_saved_pages_param_process(gx_device_printer *pdev, byte *param, int param_size) { byte *param_scan = param; int param_left = param_size; byte *token; int token_size, code, printed_count, collated_copies = 1; int tmp_num; /* during token scanning loop */ int erasepage_needed = 0; while (pdev->child) pdev = (gx_device_printer *)pdev->child; while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) { switch (param_find_key(token, token_size)) { case PARAM_BEGIN: if (pdev->saved_pages_list == NULL) { if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL) return_error(gs_error_VMerror); /* We need to change to clist mode. Always uses clist when saving pages */ pdev->saved_pages_list->save_banding_type = pdev->space_params.banding_type; pdev->space_params.banding_type = BandingAlways; if ((code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height)) < 0) return code; erasepage_needed |= 1; } break; case PARAM_END: if (pdev->saved_pages_list != NULL) { /* restore to what was set before the "begin" */ pdev->space_params.banding_type = pdev->saved_pages_list->save_banding_type; gx_saved_pages_list_free(pdev->saved_pages_list); pdev->saved_pages_list = NULL; /* We may need to change from clist mode since we forced clist when saving pages */ code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height); if (code < 0) return code; erasepage_needed |= 1; /* make sure next page is erased */ } break; case PARAM_FLUSH: if (pdev->saved_pages_list != NULL) { /* Save the collated copy count so the list we return will have it */ collated_copies = pdev->saved_pages_list->collated_copies; gx_saved_pages_list_free(pdev->saved_pages_list); } /* Always return with an empty list, even if we weren't saving previously */ if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL) return_error(gs_error_VMerror); /* restore the original count */ pdev->saved_pages_list->collated_copies = collated_copies; break; case PARAM_COPIES: /* copies requires a number next */ /* make sure that we have a list */ if (pdev->saved_pages_list == NULL) { return_error(gs_error_rangecheck); /* copies not allowed before a 'begin' */ } /* Move to past 'copies' token */ param_left -= token - param_scan + token_size; param_scan = token + token_size; if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL || param_find_key(token, token_size) != PARAM_NUMBER) { emprintf(pdev->memory, "gx_saved_pages_param_process: copies not followed by number.\n"); return_error(gs_error_typecheck); } if (sscanf((const char *)token, "%d", &tmp_num) != 1) { emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); code = gs_error_typecheck; return code; } pdev->saved_pages_list->collated_copies = tmp_num; /* save it for our loop */ break; case PARAM_PRINT: /* Move to past 'print' token */ param_left -= token - param_scan + token_size; param_scan = token + token_size; code = param_left; /* in case list is NULL, skip rest of string */ if (pdev->saved_pages_list != NULL) { if ((code = gx_saved_pages_list_print(pdev, pdev->saved_pages_list, param_scan, param_left, &printed_count)) < 0) return code; erasepage_needed |= 1; /* make sure next page is erased */ } /* adjust for all of the print parameters */ token_size += code; break; /* We are expecting an action keyword, so other keywords and tokens */ /* are not valid here (mostly the 'print' parameters). */ default: { byte *bad_token = gs_alloc_string(pdev->memory, token_size+1, "saved_pages_param_process"); byte *param_string = gs_alloc_string(pdev->memory, param_size+1, "saved_pages_param_process"); if (bad_token != NULL && param_string != NULL) { memcpy(bad_token, token, token_size); bad_token[token_size] = 0; /* terminate string */ memcpy(param_string, param, param_size); param_string[param_size] = 0; /* terminate string */ emprintf2(pdev->memory, "*** Invalid saved-pages token '%s'\n *** in param string '%s'\n", bad_token, param_string); gs_free_string(pdev->memory, bad_token, token_size+1, "saved_pages_param_process"); gs_free_string(pdev->memory, param_string, param_size+1, "saved_pages_param_process"); } } } /* Move to next token */ param_left -= token - param_scan + token_size; param_scan = token + token_size; } return erasepage_needed; }