diff options
Diffstat (limited to 'psi/zpdfops.c')
-rw-r--r-- | psi/zpdfops.c | 690 |
1 files changed, 426 insertions, 264 deletions
diff --git a/psi/zpdfops.c b/psi/zpdfops.c index 4c01de03..45bd7803 100644 --- a/psi/zpdfops.c +++ b/psi/zpdfops.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2021 Artifex Software, Inc. +/* Copyright (C) 2001-2022 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -25,6 +25,7 @@ #include "iminst.h" #include "dstack.h" +#include "gsicc_profilecache.h" #endif #include "ghost.h" @@ -272,51 +273,123 @@ zsaslprep(i_ctx_t *i_ctx_p) #if defined(BUILD_PDF) && BUILD_PDF == 1 -/* - This cannot fail. If gs doesn't have these settings it will never reach here. - Because the lives of the string values here are all tied to the Postscript - context, and the Postscript context *must* outlast the pdfi context, we can - safely just take references, marking the strings as "persistent" so destroying - the pdfi context doesn't try to free the string bodies. - */ -static void zpdfi_populate_search_paths(i_ctx_t *i_ctx_p, pdf_context *ctx) +static int zpdfi_populate_search_paths(i_ctx_t *i_ctx_p, pdf_context *ctx) { + int code = 0; /* This should only be called once per pdfi context if the paths are already populated, just skip it. */ if (ctx->search_paths.resource_paths == NULL) { ref *l2dictref, *grdref, *fpathref; - int code, i; + int i; const gs_file_path *pfpath = i_ctx_p->lib_path; gs_main_instance *minst = get_minst_from_memory(imemory); code = dict_find_string(systemdict, "pssystemparams", &l2dictref); if (code >= 0 && r_has_type(l2dictref, t_dictionary)) { code = dict_find_string(l2dictref, "GenericResourceDir", &grdref); if (code >= 0 && r_has_type(grdref, t_string)) { - ctx->search_paths.genericresourcedir.data = grdref->value.const_bytes; + ctx->search_paths.genericresourcedir.data = gs_alloc_bytes(ctx->memory, r_size(grdref), "zpdfi_populate_search_paths"); + if (ctx->search_paths.genericresourcedir.data == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memcpy((char *)ctx->search_paths.genericresourcedir.data, grdref->value.const_bytes, r_size(grdref)); ctx->search_paths.genericresourcedir.size = r_size(grdref); - ctx->search_paths.genericresourcedir.persistent = true; + ctx->search_paths.genericresourcedir.persistent = false; } } + ctx->search_paths.resource_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(&pfpath->list), "array of paths"); + if (ctx->search_paths.resource_paths == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memset(ctx->search_paths.resource_paths, 0x00, sizeof(gs_param_string) * r_size(&pfpath->list)); + ctx->search_paths.num_resource_paths = r_size(&pfpath->list); for (i = 0; i < r_size(&pfpath->list); i++) { const ref *prdir = pfpath->list.value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */ - ctx->search_paths.resource_paths[i].data = prdir->value.const_bytes; + ctx->search_paths.resource_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths"); + if (ctx->search_paths.resource_paths[i].data == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memcpy((char *)ctx->search_paths.resource_paths[i].data, prdir->value.const_bytes, r_size(prdir)); ctx->search_paths.resource_paths[i].size = r_size(prdir); - ctx->search_paths.resource_paths[i].persistent = true; + ctx->search_paths.resource_paths[i].persistent = false; } code = dict_find_string(systemdict, "FONTPATH", &fpathref); - ctx->search_paths.font_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(fpathref), "array of font paths"); - ctx->search_paths.num_font_paths = r_size(fpathref); - for (i = 0; i < r_size(fpathref); i++) { - const ref *prdir = pfpath->list.value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */ - ctx->search_paths.resource_paths[i].data = prdir->value.const_bytes; - ctx->search_paths.resource_paths[i].size = r_size(prdir); - ctx->search_paths.resource_paths[i].persistent = true; + if (code >= 0 && r_has_type(fpathref, t_array)) { + ctx->search_paths.font_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(fpathref), "array of font paths"); + memset(ctx->search_paths.font_paths, 0x00, sizeof(gs_param_string) * r_size(fpathref)); + + ctx->search_paths.num_font_paths = r_size(fpathref); + for (i = 0; i < r_size(fpathref); i++) { + const ref *prdir = fpathref->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */ + ctx->search_paths.font_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths"); + if (ctx->search_paths.font_paths[i].data == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memcpy((char *)ctx->search_paths.font_paths[i].data, prdir->value.const_bytes, r_size(prdir)); + ctx->search_paths.font_paths[i].size = r_size(prdir); + ctx->search_paths.font_paths[i].persistent = false; + } } ctx->search_paths.search_here_first = minst->search_here_first; } +done: + return code >= 0 ? 0 : code; +} + +static int zpdfi_populate_fontmap_files(i_ctx_t *i_ctx_p, pdf_context *ctx) +{ + int code, i; + ref *fontmaps; + + code = dict_find_string(systemdict, "FONTMAP", &fontmaps); + if (code >= 0 && r_has_type(fontmaps, t_array)) { + ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string) * r_size(fontmaps), "array of fontmap files"); + if (ctx->fontmapfiles != 0) { + memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * r_size(fontmaps)); + ctx->num_fontmapfiles = r_size(fontmaps); + for (i = 0; i < r_size(fontmaps); i++) { + const ref *fmapfile = fontmaps->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */ + ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, r_size(fmapfile), "zpdfi_populate_fontmap_files"); + if (ctx->fontmapfiles[i].data == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memcpy((char *)ctx->fontmapfiles[i].data, fmapfile->value.const_bytes, r_size(fmapfile)); + ctx->fontmapfiles[i].size = r_size(fmapfile); + } + } + else { + code = gs_note_error(gs_error_VMerror); + goto done; + } + } + else if (code >= 0 && r_has_type(fontmaps, t_string)) { + ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string), "array of fontmap files"); + if (ctx->fontmapfiles != 0) { + ctx->num_fontmapfiles = 1; + ctx->fontmapfiles[0].data = gs_alloc_bytes(ctx->memory, r_size(fontmaps), "zpdfi_populate_fontmap_files"); + if (ctx->fontmapfiles[0].data == NULL) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + memcpy((char *)ctx->fontmapfiles[0].data, fontmaps->value.const_bytes, r_size(fontmaps)); + ctx->fontmapfiles[0].size = r_size(fontmaps); + } + else { + code = gs_note_error(gs_error_VMerror); + goto done; + } + } + else + code = 0; +done: + return code; } /* @@ -329,8 +402,44 @@ typedef struct pdfctx_s { gs_memory_t *pdf_memory; /* The 'wrapped' memory allocator used by the PDF interpreter. Not exposed to garbager */ gs_memory_t *pdf_stream_memory; /* The memory allocator used to copy the PostScript stream to pdf_stream. Not exposed to garbager */ stream *pdf_stream; + gsicc_profile_cache_t *profile_cache; + gs_memory_t *cache_memory; /* The memory allocator used to allocate the working (GC'ed) profile cache */ } pdfctx_t; +/* There is some unfortunately necessary complication in the structure above regarding the ICC profile cache. + * Initially the problem was due to adding the colour space name to the 'interpreter data' part of the colour + * space, in order to be able to identify the case where we switch to the current colour space. + * + * This caused problems with ICC spaces, because these maintain a reference to the colour space. If the profile + * was stored in the PostScript profile cache (which it would be, because the profile cache is stored in the + * grapchis state, which we inherit from the PostScript interpreter) then it would outlive the PDF interpreter, + * and when we came to free the cache it would try to free the colour space, which would try to free the PDF + * name object, which had already been freed. + * + * To work around this we replaced the profile cache in the graphics state with the profile cache from the PDF + * interpreter. Now when we free the PDF profile cache, it frees the colour spaces, and the PDF names, while they + * are still valid. + * + * However, we then discovered that the garbage collector could reclaim the colour spaces. This happens because + * no GC-visible object declares it has a reference to the colour space. It doesn't matter that the colour + * space has been counted up, the GC frees it. Now the profile cache in pdfi is pointing to a colour space which + * has gone away.... + * + * To get round this, we create a brand-new profile cache, using GC'ed memory (well actually the interpreter + * allocator, which is GC'ed for Ghostscript). When we switch to pdfi we replace the graphics state pdfi is + * using with the one from the PostScript environment, and at the same time we swap out the profile cache + * being used by that graphics state, so it uses our new one. On return to PostScript we swap them back. + * This allows the lifetime of the profiles in the profile cache to be correct, because they are visible to the + * garbage collector (the PDF context is a GC-visible object and enumerates it's member profile cache) + * When we finalize the PDF context we count down the profile cache which dereferences all its entries. This + * effectively frees the colour space (the memory may not be reclaimed yet) which calls the interpreter + * specific cleanup, which frees the (still valid at this point) PDF name object and sets the pointer to NULL. + * + * The net result is that we have the profiles visible to the garbage collector during their lifetime, but + * still have control over the cache, so we can empty it of the profiles created for pdfi when we close the + * PDF interpreter. + */ + /* Structure descriptors */ static void pdfctx_finalize(const gs_memory_t *cmem, void *vptr); @@ -339,11 +448,11 @@ gs_private_st_composite_final(st_pdfctx_t, pdfctx_t, "pdfctx_struct",\ static ENUM_PTRS_BEGIN(pdfctx_enum_ptrs) return 0; -ENUM_PTR2(0, pdfctx_t, ps_stream, pdf_stream); +ENUM_PTR3(0, pdfctx_t, ps_stream, pdf_stream, profile_cache); ENUM_PTRS_END static RELOC_PTRS_BEGIN(pdfctx_reloc_ptrs); -RELOC_PTR2(pdfctx_t, ps_stream, pdf_stream); +RELOC_PTR3(pdfctx_t, ps_stream, pdf_stream, profile_cache); RELOC_PTRS_END static void @@ -354,6 +463,10 @@ pdfctx_finalize(const gs_memory_t *cmem, void *vptr) * on the same object - hence we null the entries. */ + if (pdfctx->profile_cache != NULL) { + rc_decrement(pdfctx->profile_cache, "free the working profile cache"); + pdfctx->profile_cache = NULL; + } if (cmem != NULL) { if (pdfctx->ctx != NULL) { if (pdfctx->pdf_stream) { @@ -385,9 +498,7 @@ static int zPDFstream(i_ctx_t *i_ctx_p) int code = 0; stream *s; pdfctx_t *pdfctx; - gs_gstate *pgs = NULL; - gs_gstate_client_procs procs; - void *client_data; + pdfi_switch_t i_switch; check_op(2); @@ -409,20 +520,13 @@ static int zPDFstream(i_ctx_t *i_ctx_p) *(pdfctx->pdf_stream) = *(pdfctx->ps_stream); - pgs = pdfctx->ctx->pgs; - procs = igs->client_procs; - client_data = igs->client_data; - pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs); - pdfctx->ctx->pgs = igs; + code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache); - code = pdfi_set_input_stream(pdfctx->ctx, pdfctx->pdf_stream); + if (code >= 0) { + code = pdfi_set_input_stream(pdfctx->ctx, pdfctx->pdf_stream); - pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs); - if (code == 0) - code = gs_grestore(igs); - else - (void)gs_grestore(igs); - pdfctx->ctx->pgs = pgs; + pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch); + } if (code < 0) { memset(pdfctx->pdf_stream, 0x00, sizeof(stream)); @@ -445,9 +549,7 @@ static int zPDFfile(i_ctx_t *i_ctx_p) pdfctx_t *pdfctx; char pdffilename[gp_file_name_sizeof]; int code = 0; - gs_gstate *pgs = NULL; - gs_gstate_client_procs procs; - void *client_data; + pdfi_switch_t i_switch; check_op(2); @@ -467,20 +569,13 @@ static int zPDFfile(i_ctx_t *i_ctx_p) memcpy(pdffilename, (op - 1)->value.bytes, r_size(op - 1)); pdffilename[r_size(op - 1)] = 0; - pgs = pdfctx->ctx->pgs; - procs = igs->client_procs; - client_data = igs->client_data; - pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs); - pdfctx->ctx->pgs = igs; + code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache); - code = pdfi_open_pdf_file(pdfctx->ctx, pdffilename); + if (code >= 0) { + code = pdfi_open_pdf_file(pdfctx->ctx, pdffilename); - pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs); - if (code == 0) - code = gs_grestore(igs); - else - (void)gs_grestore(igs); - pdfctx->ctx->pgs = pgs; + pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch); + } if (code < 0) return code; @@ -500,12 +595,18 @@ static int zPDFclose(i_ctx_t *i_ctx_p) check_type(*op, t_pdfctx); pdfctx = r_ptr(op, pdfctx_t); + if (pdfctx->profile_cache != NULL) { + rc_decrement(pdfctx->profile_cache, "free the working profile cache"); + pdfctx->profile_cache = NULL; + } + if (pdfctx->ctx != NULL) { + pdfi_report_errors(pdfctx->ctx); if (pdfctx->ps_stream) { /* Detach the PostScript stream from the PDF context, otherwise the * close code will close the main stream */ - pdfctx->ctx->main_stream = NULL; + pdfctx->ctx->main_stream->s = NULL; } code = pdfi_free_context(pdfctx->ctx); pdfctx->ctx = NULL; @@ -533,75 +634,79 @@ static int zPDFinfo(i_ctx_t *i_ctx_p) check_type(*(op), t_pdfctx); pdfctx = r_ptr(op, pdfctx_t); - code = dict_create(4, op); - if (code < 0) - return code; - - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1); - if (code < 0) - return code; - - make_int(&intref, pdfctx->ctx->num_pages); + if (pdfctx->pdf_stream != NULL) { + code = dict_create(4, op); + if (code < 0) + return code; - code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack); - if (code < 0) - return code; + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1); + if (code < 0) + return code; - /* Code to process Collections. The pdfi_prep_collection() function returns an - * array of descriptions and filenames. Because the descriptions can contain - * UTF16-BE encoded data we can't sue a NULL terminated string, so the description - * strings are terminated with a triple-NULL sequence of bytes. - * We copy the contents into a PostScript array, which we store in the info - * dictionary using the /Collection key. - */ - if (pdfctx->ctx->Collection != NULL) { - code = pdfi_prep_collection(pdfctx->ctx, &TotalFiles, &names_array); - if (code >= 0 && TotalFiles > 0) { - uint size; - ref collection, stringref; + make_int(&intref, pdfctx->ctx->num_pages); - code = ialloc_ref_array(&collection, a_all, TotalFiles * 2, "names array"); - if (code < 0) - goto error; + code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack); + if (code < 0) + return code; - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Collection", 10, &nameref, 1); - if (code < 0) - goto error; + /* Code to process Collections. The pdfi_prep_collection() function returns an + * array of descriptions and filenames. Because the descriptions can contain + * UTF16-BE encoded data we can't sue a NULL terminated string, so the description + * strings are terminated with a triple-NULL sequence of bytes. + * We copy the contents into a PostScript array, which we store in the info + * dictionary using the /Collection key. + */ + if (pdfctx->ctx->Collection != NULL) { + code = pdfi_prep_collection(pdfctx->ctx, &TotalFiles, &names_array); + if (code >= 0 && TotalFiles > 0) { + uint size; + ref collection, stringref; + + code = ialloc_ref_array(&collection, a_all, TotalFiles * 2, "names array"); + if (code < 0) + goto error; - code = dict_put(op, &nameref, &collection, &i_ctx_p->dict_stack); - if (code < 0) - goto error; + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Collection", 10, &nameref, 1); + if (code < 0) + goto error; - for (ix=0; ix < TotalFiles * 2; ix++) { - char *ptr = names_array[ix]; - byte *sbody; - ref *pelement; - - size = 0; - do { - if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00) - break; - ptr++; - size++; - } while (1); - sbody = ialloc_string(size, "string"); - if (sbody == 0) { - code = gs_error_VMerror; + code = dict_put(op, &nameref, &collection, &i_ctx_p->dict_stack); + if (code < 0) goto error; + + for (ix=0; ix < TotalFiles * 2; ix++) { + char *ptr = names_array[ix]; + byte *sbody; + ref *pelement; + + size = 0; + do { + if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00) + break; + ptr++; + size++; + } while (1); + sbody = ialloc_string(size, "string"); + if (sbody == 0) { + code = gs_error_VMerror; + goto error; + } + make_string(&stringref, a_all | icurrent_space, size, sbody); + memset(sbody, 0x00, size); + memcpy(sbody, names_array[ix], size); + gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames"); + names_array[ix] = NULL; + pelement = collection.value.refs + ix; + ref_assign_old(&collection, pelement, &stringref, "put names string"); } - make_string(&stringref, a_all | icurrent_space, size, sbody); - memset(sbody, 0x00, size); - memcpy(sbody, names_array[ix], size); - gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames"); - names_array[ix] = NULL; - pelement = collection.value.refs + ix; - ref_assign_old(&collection, pelement, &stringref, "put names string"); } + gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames"); + code = 0; } - gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames"); - code = 0; } - + else { + return_error(gs_error_ioerror); + } return code; error: @@ -618,9 +723,7 @@ static int zPDFpageinfo(i_ctx_t *i_ctx_p) int page = 0, code = 0, i; pdfctx_t *pdfctx; pdf_info_t info; - gs_gstate *pgs = NULL; - gs_gstate_client_procs procs; - void *client_data; + pdfi_switch_t i_switch; check_op(2); @@ -630,163 +733,160 @@ static int zPDFpageinfo(i_ctx_t *i_ctx_p) check_type(*(op - 1), t_pdfctx); pdfctx = r_ptr(op - 1, pdfctx_t); - pgs = pdfctx->ctx->pgs; - procs = igs->client_procs; - client_data = igs->client_data; - pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs); - pdfctx->ctx->pgs = igs; - - code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &info); - - pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs); - if (code == 0) - code = gs_grestore(igs); - else - (void)gs_grestore(igs); - pdfctx->ctx->pgs = pgs; + if (pdfctx->pdf_stream != NULL) { + code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache); - if (code < 0) - return code; + if (code >= 0) { + code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &info); - pop(1); - op = osp; - - code = dict_create(4, op); - if (code < 0) - return code; - - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"HasAnnots", 9, &nameref, 1); - if (code < 0) - return code; - make_bool(&boolref, false); - code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack); - if (code < 0) - return code; + pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch); + } - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UsesTransparency", 16, &nameref, 1); - if (code < 0) - return code; - make_bool(&boolref, info.HasTransparency); - code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack); - if (code < 0) - return code; + if (code < 0) + return code; - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumSpots", 8, &nameref, 1); - if (code < 0) - return code; - make_int(&numref, info.NumSpots); - code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack); - if (code < 0) - return code; + pop(1); + op = osp; - if (info.boxes & MEDIA_BOX) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"MediaBox", 8, &nameref, 1); + code = dict_create(4, op); if (code < 0) return code; - code = ialloc_ref_array(&aref, a_all, 4, "array"); + + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"HasAnnots", 9, &nameref, 1); if (code < 0) return code; - refset_null(aref.value.refs, 4); - for (i=0;i < 4;i++) { - make_real(&numref, info.MediaBox[i]); - eltp = aref.value.refs + i; - ref_assign_old(&aref, eltp, &numref, "put"); - } - code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + make_bool(&boolref, false); + code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack); if (code < 0) return code; - } - if (info.boxes & CROP_BOX) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"CropBox", 7, &nameref, 1); + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UsesTransparency", 16, &nameref, 1); if (code < 0) return code; - code = ialloc_ref_array(&aref, a_all, 4, "array"); + make_bool(&boolref, info.HasTransparency); + code = dict_put(op, &nameref, &boolref, &i_ctx_p->dict_stack); if (code < 0) return code; - refset_null(aref.value.refs, 4); - for (i=0;i < 4;i++) { - make_real(&numref, info.CropBox[i]); - eltp = aref.value.refs + i; - ref_assign_old(&aref, eltp, &numref, "put"); - } - code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); - if (code < 0) - return code; - } - if (info.boxes & TRIM_BOX) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"TrimBox", 7, &nameref, 1); + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumSpots", 8, &nameref, 1); if (code < 0) return code; - code = ialloc_ref_array(&aref, a_all, 4, "array"); + make_int(&numref, info.NumSpots); + code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack); if (code < 0) return code; - refset_null(aref.value.refs, 4); - for (i=0;i < 4;i++) { - make_real(&numref, info.TrimBox[i]); - eltp = aref.value.refs + i; - ref_assign_old(&aref, eltp, &numref, "put"); + + if (info.boxes & MEDIA_BOX) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"MediaBox", 8, &nameref, 1); + if (code < 0) + return code; + code = ialloc_ref_array(&aref, a_all, 4, "array"); + if (code < 0) + return code; + refset_null(aref.value.refs, 4); + for (i=0;i < 4;i++) { + make_real(&numref, info.MediaBox[i]); + eltp = aref.value.refs + i; + ref_assign_old(&aref, eltp, &numref, "put"); + } + code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + if (code < 0) + return code; } - code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); - if (code < 0) - return code; - } - if (info.boxes & ART_BOX) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"ArtBox", 6, &nameref, 1); - if (code < 0) - return code; - code = ialloc_ref_array(&aref, a_all, 4, "array"); - if (code < 0) - return code; - refset_null(aref.value.refs, 4); - for (i=0;i < 4;i++) { - make_real(&numref, info.ArtBox[i]); - eltp = aref.value.refs + i; - ref_assign_old(&aref, eltp, &numref, "put"); + if (info.boxes & CROP_BOX) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"CropBox", 7, &nameref, 1); + if (code < 0) + return code; + code = ialloc_ref_array(&aref, a_all, 4, "array"); + if (code < 0) + return code; + refset_null(aref.value.refs, 4); + for (i=0;i < 4;i++) { + make_real(&numref, info.CropBox[i]); + eltp = aref.value.refs + i; + ref_assign_old(&aref, eltp, &numref, "put"); + } + code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + if (code < 0) + return code; } - code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); - if (code < 0) - return code; - } - if (info.boxes & BLEED_BOX) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"BleedBox", 8, &nameref, 1); - if (code < 0) - return code; - code = ialloc_ref_array(&aref, a_all, 4, "array"); - if (code < 0) - return code; - refset_null(aref.value.refs, 4); - for (i=0;i < 4;i++) { - make_real(&numref, info.BleedBox[i]); - eltp = aref.value.refs + i; - ref_assign_old(&aref, eltp, &numref, "put"); + if (info.boxes & TRIM_BOX) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"TrimBox", 7, &nameref, 1); + if (code < 0) + return code; + code = ialloc_ref_array(&aref, a_all, 4, "array"); + if (code < 0) + return code; + refset_null(aref.value.refs, 4); + for (i=0;i < 4;i++) { + make_real(&numref, info.TrimBox[i]); + eltp = aref.value.refs + i; + ref_assign_old(&aref, eltp, &numref, "put"); + } + code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + if (code < 0) + return code; } - code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); - if (code < 0) - return code; - } - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Rotate", 6, &nameref, 1); - if (code < 0) - return code; - make_real(&numref, info.Rotate); - code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack); - if (code < 0) - return code; + if (info.boxes & ART_BOX) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"ArtBox", 6, &nameref, 1); + if (code < 0) + return code; + code = ialloc_ref_array(&aref, a_all, 4, "array"); + if (code < 0) + return code; + refset_null(aref.value.refs, 4); + for (i=0;i < 4;i++) { + make_real(&numref, info.ArtBox[i]); + eltp = aref.value.refs + i; + ref_assign_old(&aref, eltp, &numref, "put"); + } + code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + if (code < 0) + return code; + } - if (info.UserUnit != 1) { - code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UserUnit", 8, &nameref, 1); + if (info.boxes & BLEED_BOX) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"BleedBox", 8, &nameref, 1); + if (code < 0) + return code; + code = ialloc_ref_array(&aref, a_all, 4, "array"); + if (code < 0) + return code; + refset_null(aref.value.refs, 4); + for (i=0;i < 4;i++) { + make_real(&numref, info.BleedBox[i]); + eltp = aref.value.refs + i; + ref_assign_old(&aref, eltp, &numref, "put"); + } + code = dict_put(op, &nameref, &aref, &i_ctx_p->dict_stack); + if (code < 0) + return code; + } + + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Rotate", 6, &nameref, 1); if (code < 0) return code; - make_real(&numref, info.UserUnit); + make_real(&numref, info.Rotate); code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack); if (code < 0) return code; - } + if (info.UserUnit != 1) { + code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"UserUnit", 8, &nameref, 1); + if (code < 0) + return code; + make_real(&numref, info.UserUnit); + code = dict_put(op, &nameref, &numref, &i_ctx_p->dict_stack); + if (code < 0) + return code; + } + } + else { + return_error(gs_error_ioerror); + } return 0; } @@ -809,9 +909,7 @@ static int zPDFdrawpage(i_ctx_t *i_ctx_p) int code = 0; uint64_t page = 0; pdfctx_t *pdfctx; - gs_gstate *pgs = NULL; - gs_gstate_client_procs procs; - void *client_data; + pdfi_switch_t i_switch; check_op(2); @@ -821,27 +919,28 @@ static int zPDFdrawpage(i_ctx_t *i_ctx_p) check_type(*(op - 1), t_pdfctx); pdfctx = r_ptr(op - 1, pdfctx_t); - code = gs_gsave(igs); - if (code < 0) - return code; - - pgs = pdfctx->ctx->pgs; - procs = igs->client_procs; - client_data = igs->client_data; - pdfi_gstate_from_PS(pdfctx->ctx, igs, &client_data, &procs); - pdfctx->ctx->pgs = igs; + if (pdfctx->pdf_stream != NULL) { + code = gs_gsave(igs); + if (code < 0) + return code; - code = pdfi_page_render(pdfctx->ctx, page, false); - if (code >= 0) - pop(2); + code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache); - pdfi_gstate_to_PS(pdfctx->ctx, igs, client_data, &procs); - if (code == 0) - code = gs_grestore(igs); - else - (void)gs_grestore(igs); - pdfctx->ctx->pgs = pgs; + if (code >= 0) { + code = pdfi_page_render(pdfctx->ctx, page, false); + if (code >= 0) + pop(2); + pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch); + } + if (code == 0) + code = gs_grestore(igs); + else + (void)gs_grestore(igs); + } + else { + return_error(gs_error_ioerror); + } return code; } @@ -906,6 +1005,12 @@ static int zPDFInit(i_ctx_t *i_ctx_p) pdfctx->ps_stream = NULL; pdfctx->pdf_stream = NULL; pdfctx->pdf_stream_memory = NULL; + pdfctx->profile_cache = gsicc_profilecache_new(imemory); + if (pdfctx->profile_cache == NULL) { + code = gs_note_error(gs_error_VMerror); + goto error; + } + pdfctx->cache_memory = imemory; ctx = pdfi_create_context(cmem); if (ctx == NULL) { @@ -914,7 +1019,7 @@ static int zPDFInit(i_ctx_t *i_ctx_p) } pdfctx->ctx = ctx; - get_zfont_glyph_name((void **)&pdfctx->ctx->get_glyph_name); + get_zfont_glyph_name(&pdfctx->ctx->get_glyph_name); pdfctx->ctx->get_glyph_index = zpdfi_glyph_index; if (ref_stack_count(&o_stack) > 0 && r_has_type(op, t_dictionary)) { @@ -984,7 +1089,7 @@ static int zPDFInit(i_ctx_t *i_ctx_p) pdfctx->ctx->args.last_page = pvalueref->value.intval; } - if (dict_find_string(pdictref, "NOCIDFALLBACK", &pvalueref) > 0) { + if (dict_find_string(pdictref, "PDFNOCIDFALLBACK", &pvalueref) > 0) { if (!r_has_type(pvalueref, t_boolean)) goto error; pdfctx->ctx->args.nocidfallback = pvalueref->value.boolval; @@ -996,6 +1101,21 @@ static int zPDFInit(i_ctx_t *i_ctx_p) pdfctx->ctx->args.no_pdfmark_outlines = pvalueref->value.boolval; } + /* This one can be a boolean OR an integer */ + if (dict_find_string(pdictref, "UsePDFX3Profile", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_boolean)) { + if (!r_has_type(pvalueref, t_integer)) + goto error; + else { + pdfctx->ctx->args.UsePDFX3Profile = true; + pdfctx->ctx->args.PDFX3Profile_num = pvalueref->value.intval; + } + } else { + pdfctx->ctx->args.UsePDFX3Profile = pvalueref->value.boolval; + pdfctx->ctx->args.PDFX3Profile_num = 0; + } + } + if (dict_find_string(pdictref, "NO_PDFMARK_DESTS", &pvalueref) > 0) { if (!r_has_type(pvalueref, t_boolean)) goto error; @@ -1056,6 +1176,12 @@ static int zPDFInit(i_ctx_t *i_ctx_p) pdfctx->ctx->args.preserveannots = pvalueref->value.boolval; } + if (dict_find_string(pdictref, "PreserveMarkedContent", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_boolean)) + goto error; + pdfctx->ctx->args.preservemarkedcontent = pvalueref->value.boolval; + } + if (dict_find_string(pdictref, "NoUserUnit", &pvalueref) > 0) { if (!r_has_type(pvalueref, t_boolean)) goto error; @@ -1091,21 +1217,57 @@ static int zPDFInit(i_ctx_t *i_ctx_p) if (code < 0) goto error; } + if (dict_find_string(pdictref, "CIDSubstPath", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_string)) + goto error; + pdfctx->ctx->args.cidsubstpath.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF CIDSubstPath from zpdfops"); + memcpy(pdfctx->ctx->args.cidsubstpath.data, pvalueref->value.const_bytes, r_size(pvalueref)); + pdfctx->ctx->args.cidsubstpath.size = r_size(pvalueref); + } + if (dict_find_string(pdictref, "CIDSubstFont", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_string)) + goto error; + pdfctx->ctx->args.cidsubstfont.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF CIDSubstPath from zpdfops"); + memcpy(pdfctx->ctx->args.cidsubstfont.data, pvalueref->value.const_bytes, r_size(pvalueref)); + pdfctx->ctx->args.cidsubstfont.size = r_size(pvalueref); + } + if (dict_find_string(pdictref, "IgnoreToUnicode", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_boolean)) + goto error; + pdfctx->ctx->args.ignoretounicode = pvalueref->value.boolval; + } + if (dict_find_string(pdictref, "NONATIVEFONTMAP", &pvalueref) > 0) { + if (!r_has_type(pvalueref, t_boolean)) + goto error; + pdfctx->ctx->args.nonativefontmap = pvalueref->value.boolval; + } code = 0; pop(1); } - zpdfi_populate_search_paths(i_ctx_p, ctx); + code = zpdfi_populate_search_paths(i_ctx_p, ctx); + if (code < 0) + goto error; + + code = zpdfi_populate_fontmap_files(i_ctx_p, ctx); + if (code < 0) + goto error; + op = osp; push(1); make_tav(op, t_pdfctx, icurrent_space | a_all, pstruct, (obj_header_t *)(pdfctx)); return 0; error: - if (ctx) + if (ctx != NULL) pdfi_free_context(ctx); /* gs_memory_chunk_unwrap() returns the "wrapped" allocator, which we don't need */ (void)gs_memory_chunk_unwrap(cmem); - if (pdfctx) { + if (pdfctx != NULL) { + pdfctx->ctx = NULL; /* Freed already above! */ + if (pdfctx->profile_cache != NULL) { + gs_free_object(imemory, pdfctx->profile_cache, "discard temporary profile cache"); + pdfctx->profile_cache = NULL; + } pdfctx->pdf_memory = NULL; gs_free_object(imemory, pdfctx, "PDFcontext"); } |