diff options
Diffstat (limited to 'pdf/pdf_optcontent.c')
-rw-r--r-- | pdf/pdf_optcontent.c | 169 |
1 files changed, 154 insertions, 15 deletions
diff --git a/pdf/pdf_optcontent.c b/pdf/pdf_optcontent.c index d0dab6c6..484d72c9 100644 --- a/pdf/pdf_optcontent.c +++ b/pdf/pdf_optcontent.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019-2021 Artifex Software, Inc. +/* Copyright (C) 2019-2022 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -18,10 +18,12 @@ #include "pdf_int.h" #include "pdf_stack.h" #include "pdf_misc.h" +#include "pdf_font_types.h" #include "pdf_gstate.h" #include "pdf_dict.h" #include "pdf_array.h" #include "pdf_doc.h" +#include "pdf_mark.h" #include "pdf_optcontent.h" @@ -301,8 +303,8 @@ pdfi_oc_is_ocg_visible(pdf_context *ctx, pdf_dict *ocdict) is_visible = pdfi_oc_check_OCG_usage(ctx, ocdict); } else { char str[100]; - memcpy(str, (const char *)type->data, type->length); - str[type->length] = '\0'; + memcpy(str, (const char *)type->data, type->length < 100 ? type->length : 99); + str[type->length < 100 ? type->length : 99] = '\0'; dmprintf1(ctx->memory, "WARNING: OC dict type is %s, expected OCG or OCMD\n", str); } @@ -432,20 +434,116 @@ int pdfi_oc_free(pdf_context *ctx) return code; } +int pdfi_op_MP(pdf_context *ctx) +{ + pdf_obj *o = NULL; + int code = 0; + + if (pdfi_count_stack(ctx) < 1) + return_error(gs_error_stackunderflow); + + if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) + goto exit; + + o = ctx->stack_top[-1]; + if (o->type != PDF_NAME) { + pdfi_pop(ctx, 1); + return_error(gs_error_typecheck); + } + + code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "MP"); + ctx->BMClevel ++; + +exit: + pdfi_pop(ctx, 1); + return code; +} + +int pdfi_op_DP(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict) +{ + pdf_name *properties = NULL; + int code = 0; + pdf_obj **objarray = NULL; + + if (pdfi_count_stack(ctx) < 2) { + pdfi_clearstack(ctx); + return gs_note_error(gs_error_stackunderflow); + } + + if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) + goto exit; + + if ((ctx->stack_top[-2])->type != PDF_NAME) { + code = gs_note_error(gs_error_typecheck); + goto exit; + } + + objarray = (pdf_obj **)gs_alloc_bytes(ctx->memory, 2 * sizeof(pdf_obj *), "pdfi_op_DP"); + if (objarray == NULL) { + code = gs_note_error(gs_error_VMerror); + goto exit; + } + + objarray[0] = ctx->stack_top[-2]; + + if ((ctx->stack_top[-1])->type == PDF_NAME) { + code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)ctx->stack_top[-1], stream_dict, page_dict, (pdf_obj **)&properties); + if(code < 0) + goto exit; + if (properties->type != PDF_DICT) { + code = gs_note_error(gs_error_typecheck); + goto exit; + } + objarray[1] = (pdf_obj *)properties; + } else { + if ((ctx->stack_top[-1])->type != PDF_DICT) { + code = gs_note_error(gs_error_VMerror); + goto exit; + } + objarray[1] = ctx->stack_top[-1]; + } + + code = pdfi_pdfmark_from_objarray(ctx, objarray, 2, NULL, "DP"); + + exit: + if (objarray != NULL) + gs_free_object(ctx->memory, objarray, "free pdfi_op_DP"); + pdfi_pop(ctx, 2); /* pop args */ + pdfi_countdown(properties); + return code; +} + /* begin marked content sequence */ -/* TODO: Incomplete implementation, it is ignoring the argument */ int pdfi_op_BMC(pdf_context *ctx) { - if (pdfi_count_stack(ctx) >= 1) { + pdf_obj *o = NULL; + int code = 0; + + /* This will also prevent us writing out an EMC if the BMC is in any way invalid */ + ctx->BDCWasOC = true; + + if (pdfi_count_stack(ctx) < 1) + return_error(gs_error_stackunderflow); + + if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) + goto exit; + + o = ctx->stack_top[-1]; + if (o->type != PDF_NAME) { pdfi_pop(ctx, 1); - } else - pdfi_clearstack(ctx); + return_error(gs_error_typecheck); + } + + ctx->BDCWasOC = false; + code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "BMC"); ctx->BMClevel ++; - return 0; + +exit: + pdfi_pop(ctx, 1); + return code; } /* begin marked content sequence with property list */ -/* TODO: Incomplete implementation, only tries to do something sensible for OC */ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict) { pdf_name *tag = NULL; @@ -453,28 +551,62 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict) pdf_dict *oc_dict = NULL; int code = 0; bool ocg_is_visible; + pdf_obj **objarray = NULL; + + /* This will also prevent us writing out an EMC if the BDC is in any way invalid */ + ctx->BDCWasOC = true; if (pdfi_count_stack(ctx) < 2) { - /* TODO: Flag error? */ pdfi_clearstack(ctx); - return 0; + return gs_note_error(gs_error_stackunderflow); } ctx->BMClevel ++; - /* Check if second arg is OC and handle it if so */ tag = (pdf_name *)ctx->stack_top[-2]; if (tag->type != PDF_NAME) goto exit; - if (!pdfi_name_is(tag, "OC")) + + if (!pdfi_name_is(tag, "OC")) { + ctx->BDCWasOC = false; + if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) + goto exit; + + objarray = (pdf_obj **)gs_alloc_bytes(ctx->memory, 2 * sizeof(pdf_obj *), "pdfi_op_BDC"); + if (objarray == NULL) { + code = gs_note_error(gs_error_VMerror); + goto exit; + } + + objarray[0] = ctx->stack_top[-2]; + + if ((ctx->stack_top[-1])->type == PDF_NAME) { + code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)ctx->stack_top[-1], stream_dict, page_dict, (pdf_obj **)&oc_dict); + if(code < 0) + goto exit; + if (oc_dict->type != PDF_DICT) { + code = gs_note_error(gs_error_typecheck); + goto exit; + } + objarray[1] = (pdf_obj *)oc_dict; + } else { + if ((ctx->stack_top[-1])->type != PDF_DICT) { + code = gs_note_error(gs_error_VMerror); + goto exit; + } + objarray[1] = ctx->stack_top[-1]; + } + + code = pdfi_pdfmark_from_objarray(ctx, objarray, 2, NULL, "BDC"); goto exit; + } /* Check if first arg is a name and handle it if so */ /* TODO: spec says it could also be an inline dict that we should be able to handle, * but I am just matching what gs does for now, and it doesn't handle that case. */ properties = (pdf_name *)ctx->stack_top[-1]; - if (tag->type != PDF_NAME) + if (properties->type != PDF_NAME) goto exit; /* If it's a name, look it up in Properties */ @@ -491,6 +623,8 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict) code = pdfi_oc_levels_set(ctx, ctx->OFFlevels, ctx->BMClevel); exit: + if (objarray != NULL) + gs_free_object(ctx->memory, objarray, "free pdfi_op_BDC"); pdfi_pop(ctx, 2); /* pop args */ pdfi_countdown(oc_dict); return code; @@ -499,9 +633,14 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict) /* end marked content sequence */ int pdfi_op_EMC(pdf_context *ctx) { - int code; + int code, code1 = 0; + + if (ctx->device_state.writepdfmarks && ctx->args.preservemarkedcontent && !ctx->BDCWasOC) + code1 = pdfi_pdfmark_from_objarray(ctx, NULL, 0, NULL, "EMC"); code = pdfi_oc_levels_clear(ctx, ctx->OFFlevels, ctx->BMClevel); + if (code == 0) + code = code1; /* TODO: Should we flag error on too many EMC? */ if (ctx->BMClevel > 0) |