summaryrefslogtreecommitdiff
path: root/pdf
diff options
context:
space:
mode:
authorSam James <sam@gentoo.org>2022-03-29 10:27:10 +0100
committerSam James <sam@gentoo.org>2022-04-17 12:53:05 +0100
commit085bde903b9e684c3c1160e4df912bea9a660997 (patch)
treec4f5e6e9f2422e869ca5bc0b944520d451001282 /pdf
parentImport Ghostscript 9.55 (diff)
downloadghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.tar.gz
ghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.tar.bz2
ghostscript-gpl-patches-085bde903b9e684c3c1160e4df912bea9a660997.zip
Import Ghostscript 9.56.0ghostscript-9.56
Signed-off-by: Sam James <sam@gentoo.org>
Diffstat (limited to 'pdf')
-rw-r--r--pdf/ghostpdf.c283
-rw-r--r--pdf/ghostpdf.h141
-rw-r--r--pdf/pdf.mak113
-rw-r--r--pdf/pdf_annot.c215
-rw-r--r--pdf/pdf_array.c31
-rw-r--r--pdf/pdf_array.h17
-rw-r--r--pdf/pdf_check.c92
-rw-r--r--pdf/pdf_cmap.c93
-rw-r--r--pdf/pdf_colour.c397
-rw-r--r--pdf/pdf_colour.h45
-rw-r--r--pdf/pdf_deref.c248
-rw-r--r--pdf/pdf_deref.h4
-rw-r--r--pdf/pdf_device.c6
-rw-r--r--pdf/pdf_dict.c516
-rw-r--r--pdf/pdf_dict.h19
-rw-r--r--pdf/pdf_doc.c201
-rw-r--r--pdf/pdf_errors.h56
-rw-r--r--pdf/pdf_fapi.c82
-rw-r--r--pdf/pdf_file.c175
-rw-r--r--pdf/pdf_file.h6
-rw-r--r--pdf/pdf_fmap.c948
-rw-r--r--pdf/pdf_fmap.h8
-rw-r--r--pdf/pdf_font.c494
-rw-r--r--pdf/pdf_font.h1
-rw-r--r--pdf/pdf_font0.c100
-rw-r--r--pdf/pdf_font0.h2
-rw-r--r--pdf/pdf_font1.c42
-rw-r--r--pdf/pdf_font11.c56
-rw-r--r--pdf/pdf_font1C.c746
-rw-r--r--pdf/pdf_font3.c42
-rw-r--r--pdf/pdf_fontTT.c46
-rw-r--r--pdf/pdf_fontTT.h2
-rw-r--r--pdf/pdf_fontps.c1013
-rw-r--r--pdf/pdf_fontps.h5
-rw-r--r--pdf/pdf_func.c72
-rw-r--r--pdf/pdf_gstate.c114
-rw-r--r--pdf/pdf_gstate.h3
-rw-r--r--pdf/pdf_image.c253
-rw-r--r--pdf/pdf_int.c858
-rw-r--r--pdf/pdf_loop_detect.c4
-rw-r--r--pdf/pdf_mark.c166
-rw-r--r--pdf/pdf_mark.h23
-rw-r--r--pdf/pdf_misc.c4
-rw-r--r--pdf/pdf_obj.c73
-rw-r--r--pdf/pdf_optcontent.c169
-rw-r--r--pdf/pdf_optcontent.h2
-rw-r--r--pdf/pdf_page.c97
-rw-r--r--pdf/pdf_path.c49
-rw-r--r--pdf/pdf_pattern.c47
-rw-r--r--pdf/pdf_repair.c80
-rw-r--r--pdf/pdf_sec.c147
-rw-r--r--pdf/pdf_shading.c21
-rw-r--r--pdf/pdf_text.c30
-rw-r--r--pdf/pdf_trans.c103
-rw-r--r--pdf/pdf_trans.h4
-rw-r--r--pdf/pdf_types.h31
-rw-r--r--pdf/pdf_warnings.h62
-rw-r--r--pdf/pdf_xref.c156
-rw-r--r--pdf/pdfromfs.mak2
-rw-r--r--pdf/pdftop.c71
60 files changed, 5838 insertions, 3048 deletions
diff --git a/pdf/ghostpdf.c b/pdf/ghostpdf.c
index 5080a839..8d88b090 100644
--- a/pdf/ghostpdf.c
+++ b/pdf/ghostpdf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -24,6 +24,7 @@
#include "pdf_file.h"
#include "pdf_loop_detect.h"
#include "pdf_trans.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "stream.h"
#include "strmio.h"
@@ -303,82 +304,15 @@ static int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
* 'unknown' message.
*/
const char *pdf_error_strings[] = {
- "no error",
- "no header detected",
- "header lacks a version number",
- "no startxref token found",
- "startxref offset invalid",
- "couldn't read hybrid file's XrefStm",
- "error in xref table",
- "too few entries in xref table",
- "content stream lacks endstream",
- "request for unknown filter",
- "missing white space after number",
- "malformed number",
- "invalid unescaped character '(' in string",
- "invalid object number",
- "object lacks an endobj",
- "error executing PDF token",
- "potential token is too long",
- "Page object doe snot have /Page type",
- "circular reference to indirect object",
- "couldn't repair PDF file",
- "PDF file was repaired",
- "error reading a stream",
- "obj token missing",
- "error in Page dictionary",
- "out of memory",
- "error reading page dictionary",
- "stack underflow",
- "error in stream dictionary",
- "stream inherited a resource",
- "counting down reference to freed object",
- "error in transparency XObject",
- "object lacks a required Subtype",
- "error in image colour",
- "" /* last error, should not be used */
+#define PARAM(A,B) B
+#include "pdf_errors.h"
+ "" /* last error, should not be used */
};
const char *pdf_warning_strings[] = {
- "no warning",
- "incorrect xref size",
- "used inline filter name inappropriately",
- "used inline colour space inappropriately",
- "used inline image key inappropriately",
- "recoverable image error",
- "recoverable error in image dictionary",
- "encountered more Q than q",
- "encountered more q than Q",
- "garbage left on stack",
- "stack underflow",
- "error in group definition",
- "invalid operator used in text block",
- "used invalid operator in CharProc",
- "BT found inside a text block",
- "ET found outside text block",
- "text operator outside text block",
- "degenerate text matrix",
- "bad ICC colour profile, using alternate",
- "bad ICC vs number components, using components",
- "bad value for text rendering mode",
- "error in shading",
- "error in pattern",
- "non standard operator found - ignoring",
- "number uses illegal exponent form",
- "Stream has inappropriate /Contents entry",
- "bad DecodeParms",
- "error in Mask",
- "error in annotation Appearance",
- "badly escaped name",
- "typecheck error",
- "bad trailer dictionary",
- "error in annotation",
- "failed to create ICC profile link",
- "overflowed a real reading a number, assuming 0",
- "failed to read a valid number, assuming 0",
- "A DeviceN space used the /All ink name.",
- "Couldn't retrieve MediaBox for page, using current media size",
- "" /* Last warning shuld not be used */
+#define PARAM(A,B) B
+#include "pdf_warnings.h"
+ "" /* Last warning should not be used */
};
const char *gs_error_strings[] = {
@@ -521,6 +455,37 @@ void pdfi_verbose_warning(pdf_context *ctx, int gs_error, const char *gs_lib_fun
}
}
+void pdfi_set_error_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_error pdfi_error, const char *pdfi_function_name, const char *fmt, ...)
+{
+ if (pdfi_error != 0)
+ ctx->pdf_errors[pdfi_error / (sizeof(char) * 8)] |= 1 << pdfi_error % (sizeof(char) * 8);
+ if (ctx->args.verbose_errors) {
+ char extra_info[gp_file_name_sizeof];
+ va_list args;
+
+ va_start(args, fmt);
+ (void)vsnprintf(extra_info, sizeof(extra_info), fmt, args);
+ va_end(args);
+
+ pdfi_verbose_error(ctx, gs_error, gs_lib_function, pdfi_error, pdfi_function_name, extra_info);
+ }
+}
+
+void pdfi_set_warning_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_warning pdfi_warning, const char *pdfi_function_name, const char *fmt, ...)
+{
+ ctx->pdf_warnings[pdfi_warning / (sizeof(char) * 8)] |= 1 << pdfi_warning % (sizeof(char) * 8);
+ if (ctx->args.verbose_warnings) {
+ char extra_info[gp_file_name_sizeof];
+ va_list args;
+
+ va_start(args, fmt);
+ (void)vsnprintf(extra_info, sizeof(extra_info), fmt, args);
+ va_end(args);
+
+ pdfi_verbose_warning(ctx, gs_error, gs_lib_function, pdfi_warning, pdfi_function_name, extra_info);
+ }
+}
+
void pdfi_log_info(pdf_context *ctx, const char *pdfi_function, const char *info)
{
#ifdef DEBUG
@@ -529,7 +494,7 @@ void pdfi_log_info(pdf_context *ctx, const char *pdfi_function, const char *info
#endif
}
-static void
+void
pdfi_report_errors(pdf_context *ctx)
{
int code, i, j;
@@ -872,7 +837,7 @@ int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_a
/* Start by setting up the file to be read. Apply a SubFileDecode so that, if the input stream
* is not compressed we will stop reading when we get to the end of the stream.
*/
- if (pdfi_dict_knownget_number(ctx, stream_dict, "Length", &L)) {
+ if (pdfi_dict_knownget_number(ctx, stream_dict, "Length", &L) > 0) {
code = pdfi_apply_SubFileDecode_filter(ctx, (int)L, NULL, ctx->main_stream, &SubFile_stream, false);
if (code >= 0)
@@ -1063,7 +1028,12 @@ static int pdfi_init_file(pdf_context *ctx)
}
if (ctx->Trailer) {
- code = pdfi_dict_get(ctx, ctx->Trailer, "Encrypt", &o);
+ /* See comment in pdfi_read_Root() (pdf_doc.c) for details */
+ pdf_dict *d = ctx->Trailer;
+
+ pdfi_countup(d);
+ code = pdfi_dict_get(ctx, d, "Encrypt", &o);
+ pdfi_countdown(d);
if (code < 0 && code != gs_error_undefined)
goto exit;
if (code == 0) {
@@ -1204,9 +1174,9 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
char extra_info[gp_file_name_sizeof];
if (ctx->filename)
- gs_sprintf(extra_info, "%% File %s does not appear to be a PDF file (no %%PDF in first 2Kb of file)\n", ctx->filename);
+ gs_snprintf(extra_info, sizeof(extra_info), "%% File %s does not appear to be a PDF file (no %%PDF in first 2Kb of file)\n", ctx->filename);
else
- gs_sprintf(extra_info, "%% File does not appear to be a PDF stream (no %%PDF in first 2Kb of stream)\n");
+ gs_snprintf(extra_info, sizeof(extra_info), "%% File does not appear to be a PDF stream (no %%PDF in first 2Kb of stream)\n");
pdfi_set_error(ctx, 0, NULL, E_PDF_NOHEADER, "pdfi_set_input_stream", extra_info);
} else {
@@ -1281,7 +1251,7 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
byte *b = Buffer + read;
/* Success! stop now */
- if(sscanf((char *)b, " %ld", &ctx->startxref) != 1) {
+ if(sscanf((char *)b, " %"PRIdOFFSET"", &ctx->startxref) != 1) {
dmprintf(ctx->memory, "Unable to read offset of xref from PDF file\n");
}
break;
@@ -1298,7 +1268,7 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
*/
if (last_lineend) {
leftover = last_lineend - Buffer;
- memcpy(Buffer + bytes - leftover, last_lineend, leftover);
+ memmove(Buffer + bytes - leftover, last_lineend, leftover);
bytes -= leftover;
} else
leftover = 0;
@@ -1362,7 +1332,7 @@ static size_t pdfi_grdir_path_string_match(const byte *str, size_t sl0, byte *pa
int pdfi_add_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l, bool fontpath)
{
- int i, slen, npaths = (l > 0);
+ int i, slen, npaths = (l > 0) ? 1 : 0;
const char *p = ppath;
char *ps;
const char *pe = p + l + 1;
@@ -1500,6 +1470,64 @@ static void pdfi_free_search_paths(pdf_context *ctx)
}
gs_free_object(ctx->memory, (byte *)ctx->search_paths.resource_paths, "array of paths");
gs_free_object(ctx->memory, (byte *)ctx->search_paths.font_paths, "array of font paths");
+
+ if (ctx->search_paths.genericresourcedir.persistent == false)
+ gs_free_object(ctx->memory, (byte *)ctx->search_paths.genericresourcedir.data, "generic resource directory");
+}
+
+static void pdfi_free_fontmapfiles(pdf_context *ctx)
+{
+ int i;
+ for (i = 0; i < ctx->num_fontmapfiles; i++) {
+ gs_free_object(ctx->memory, ctx->fontmapfiles[i].data, "fontmapfiles string body");
+ }
+ gs_free_object(ctx->memory, ctx->fontmapfiles, "fontmapfiles array");
+}
+
+/* The fontmap file list doesn't extend, later settings in the command line override earlier ones
+ (Unlike the "-I" search paths above).
+ */
+int pdfi_add_fontmapfiles(pdf_context *ctx, const char *ppath, int l)
+{
+ int i, nfilenames = (l > 0) ? 1 : 0;
+ const char *p = ppath;
+ char *ps;
+ const char *pe = p + l + 1;
+ int code = 0;
+
+ pdfi_free_fontmapfiles(ctx);
+
+ for (ps = (char *)p; ps < pe; ps++) {
+ if (*ps == gp_file_name_list_separator)
+ nfilenames++;
+ }
+ if (nfilenames > 0) {
+ ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string) * nfilenames, "array of fontmap files");
+ if (ctx->fontmapfiles == NULL) {
+ return_error(gs_error_VMerror);
+ }
+ else {
+ memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * nfilenames);
+ ctx->num_fontmapfiles = nfilenames;
+
+ for (i = 0; i < nfilenames; i++) {
+ for (ps = (char *)p; ps < pe; ps++) {
+ if (*ps == gp_file_name_list_separator)
+ break;
+ }
+ ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, ps - p, "fontmap file name body");
+ if (ctx->fontmapfiles[i].data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memcpy(ctx->fontmapfiles[i].data, p, ps - p);
+ ctx->fontmapfiles[i].size = ps - p;
+ p = ps + 1;
+ }
+ }
+ }
+done:
+ return code;
}
/***********************************************************************************/
@@ -1527,10 +1555,6 @@ pdf_context *pdfi_create_context(gs_memory_t *mem)
ctx = (pdf_context *) gs_alloc_bytes(pmem, sizeof(pdf_context), "pdf_create_context");
-#if PDFI_LEAK_CHECK
- ctx->memstat = mstat;
-#endif
-
pgs = gs_gstate_alloc(pmem);
if (!ctx || !pgs)
@@ -1544,6 +1568,14 @@ pdf_context *pdfi_create_context(gs_memory_t *mem)
memset(ctx, 0, sizeof(pdf_context));
ctx->memory = pmem;
+ ctx->type = PDF_CTX;
+ ctx->flags = 0;
+ ctx->refcnt = 1;
+ ctx->ctx = ctx;
+
+#if PDFI_LEAK_CHECK
+ ctx->memstat = mstat;
+#endif
ctx->stack_bot = (pdf_obj **)gs_alloc_bytes(ctx->memory, INITIAL_STACK_SIZE * sizeof (pdf_obj *), "pdf_imp_allocate_interp_stack");
if (ctx->stack_bot == NULL) {
@@ -1575,7 +1607,20 @@ pdf_context *pdfi_create_context(gs_memory_t *mem)
}
ctx->pgs = pgs;
- pdfi_gstate_set_client(ctx, pgs);
+ code = pdfi_gstate_set_client(ctx, pgs);
+ if (code < 0) {
+ gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
+ gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
+ gs_free_object(pmem, ctx, "pdf_create_context");
+ gs_gstate_free(pgs);
+ return NULL;
+ }
+
+ /* Some (but not all) path construction operations can either return
+ * an error or clamp values when out of range. In order to match Ghostscript's
+ * PDF interpreter written in PostScript, we need to clamp them.
+ */
+ gs_setlimitclamp(pgs, true);
/* Declare PDL client support for high level patterns, for the benefit
* of pdfwrite and other high-level devices
@@ -1606,6 +1651,13 @@ pdf_context *pdfi_create_context(gs_memory_t *mem)
* grestore back to the initial state, it immediately saves another one.
*/
code = gs_gsave(ctx->pgs);
+ if (code < 0) {
+ gs_free_object(ctx->memory, ctx->font_dir, "pdf_create_context");
+ gs_free_object(pmem, ctx->stack_bot, "pdf_create_context");
+ gs_gstate_free(ctx->pgs);
+ gs_free_object(pmem, ctx, "pdf_create_context");
+ return NULL;
+ }
#if REFCNT_DEBUG
ctx->UID = 1;
#endif
@@ -1734,6 +1786,16 @@ int pdfi_clear_context(pdf_context *ctx)
ctx->PagesTree = NULL;
}
+ if (ctx->args.cidsubstpath.data != NULL) {
+ gs_free_object(ctx->memory, ctx->args.cidsubstpath.data, "cidsubstpath.data");
+ ctx->args.cidsubstpath.data = NULL;
+ }
+
+ if (ctx->args.cidsubstfont.data != NULL) {
+ gs_free_object(ctx->memory, ctx->args.cidsubstfont.data, "cidsubstpath.data");
+ ctx->args.cidsubstfont.data = NULL;
+ }
+
pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
pdfi_free_cstring_array(ctx, &ctx->args.preserveannottypes);
@@ -1859,6 +1921,8 @@ int pdfi_clear_context(pdf_context *ctx)
pdfi_countdown(ctx->pdffontmap);
ctx->pdffontmap = NULL;
+ pdfi_countdown(ctx->pdfnativefontmap);
+ ctx->pdfnativefontmap = NULL;
return 0;
}
@@ -1895,7 +1959,16 @@ int pdfi_free_context(pdf_context *ctx)
}
pdfi_free_search_paths(ctx);
+ pdfi_free_fontmapfiles(ctx);
+ if (ctx->pdfcidfmap != NULL) {
+ pdfi_countdown(ctx->pdfcidfmap);
+ ctx->pdfcidfmap = NULL;
+ }
+ if (ctx->pdffontmap != NULL) {
+ pdfi_countdown(ctx->pdffontmap);
+ ctx->pdffontmap = NULL;
+ }
gs_free_object(ctx->memory, ctx, "pdfi_free_context");
#if PDFI_LEAK_CHECK
gs_memory_status(mem, &mstat);
@@ -1918,21 +1991,39 @@ int pdfi_free_context(pdf_context *ctx)
* it seems to be what happens, so we can't rely on grestore to put back the interpreter context, but must
* do so ourselves.
*
- * Hence the 'from_PS' routine fills in pointers with the current context and procs, wit the expectation that
+ * Hence the 'from_PS' routine fills in pointers with the current context and procs, with the expectation that
* these will be saved and used to restore the data in the 'to_PS' routine.
*/
-void pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, void **saved_client_data, gs_gstate_client_procs *saved_procs)
+/* NOTE see the comments in zpdfops.c just under the declaration of the pdfi_switch_t strcuture regarding
+ * complications with the ICC profile cache.
+ */
+
+int pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch, gsicc_profile_cache_t *profile_cache)
{
- *saved_client_data = pgs->client_data;
- *saved_procs = pgs->client_procs;
- pdfi_gstate_set_client(ctx, pgs);
- return;
+ int code;
+ i_switch->pgs = ctx->pgs;
+ i_switch->procs = pgs->client_procs;
+ i_switch->client_data = (void *)pgs->client_data;
+ i_switch->profile_cache = pgs->icc_profile_cache;
+ code = pdfi_gstate_set_client(ctx, pgs);
+ if (code < 0)
+ return code;
+ i_switch->psfont = pgs->font;
+ pgs->icc_profile_cache = profile_cache;
+ rc_increment(pgs->icc_profile_cache);
+ pgs->font = NULL;
+ ctx->pgs = pgs;
+ return code;
}
-void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, void *client_data, const gs_gstate_client_procs *procs)
+void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch)
{
pgs->client_procs.free(pgs->client_data, pgs->memory, pgs);
pgs->client_data = NULL;
- gs_gstate_set_client(pgs, client_data, procs, true);
- return;
+ rc_decrement(pgs->icc_profile_cache, "pdfi_gstate_to_PS");
+ pgs->icc_profile_cache = i_switch->profile_cache;
+ gs_gstate_set_client(pgs, i_switch->client_data, &i_switch->procs, true);
+ ctx->pgs->font = NULL;
+ ctx->pgs = i_switch->pgs;
+ pgs->font = i_switch->psfont;
}
diff --git a/pdf/ghostpdf.h b/pdf/ghostpdf.h
index 3cc1b8cd..49c91808 100644
--- a/pdf/ghostpdf.h
+++ b/pdf/ghostpdf.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -32,6 +32,18 @@
#define PDFI_LEAK_CHECK 0
#endif
+/* A structure for setting/resetting the interpreter graphics state
+ * and some graphics state content when switching between Ghostscript
+ * and pdfi, when running under GS.
+ */
+typedef struct pdf_context_switch {
+ gs_gstate *pgs;
+ gs_font *psfont;
+ gs_gstate_client_procs procs;
+ void *client_data;
+ void *profile_cache;
+} pdfi_switch_t;
+
/*
* The interpreter context.
*/
@@ -42,82 +54,13 @@
* how to deal with this.
*/
typedef enum pdf_error_e {
- E_PDF_NOERROR,
- E_PDF_NOHEADER,
- E_PDF_NOHEADERVERSION,
- E_PDF_NOSTARTXREF,
- E_PDF_BADSTARTXREF,
- E_PDF_BADXREFSTREAM,
- E_PDF_BADXREF,
- E_PDF_SHORTXREF,
- E_PDF_MISSINGENDSTREAM,
- E_PDF_UNKNOWNFILTER,
- E_PDF_MISSINGWHITESPACE,
- E_PDF_MALFORMEDNUMBER,
- E_PDF_UNESCAPEDSTRING,
- E_PDF_BADOBJNUMBER,
- E_PDF_MISSINGENDOBJ,
- E_PDF_TOKENERROR,
- E_PDF_KEYWORDTOOLONG,
- E_PDF_BADPAGETYPE,
- E_PDF_CIRCULARREF,
- E_PDF_UNREPAIRABLE,
- E_PDF_REPAIRED,
- E_PDF_BADSTREAM,
- E_PDF_MISSINGOBJ,
- E_PDF_BADPAGEDICT,
- E_PDF_OUTOFMEMORY,
- E_PDF_PAGEDICTERROR,
- E_PDF_STACKUNDERFLOWERROR,
- E_PDF_BADSTREAMDICT,
- E_PDF_INHERITED_STREAM_RESOURCE,
- E_PDF_DEREF_FREE_OBJ,
- E_PDF_INVALID_TRANS_XOBJECT,
- E_PDF_NO_SUBTYPE,
- E_PDF_IMAGECOLOR_ERROR,
- E_PDF_MAX_ERROR /* Must be last entry, add new errors immediately before this and update pdf_error_strings in ghostpdf.c */
+#include "pdf_errors.h"
+ E_PDF_MAX_ERROR /* last entry */
}pdf_error;
typedef enum pdf_warning_e {
- W_PDF_NOWARNING,
- W_PDF_BAD_XREF_SIZE,
- W_PDF_BAD_INLINEFILTER,
- W_PDF_BAD_INLINECOLORSPACE,
- W_PDF_BAD_INLINEIMAGEKEY,
- W_PDF_IMAGE_ERROR,
- W_PDF_BAD_IMAGEDICT,
- W_PDF_TOOMANYQ,
- W_PDF_TOOMANYq,
- W_PDF_STACKGARBAGE,
- W_PDF_STACKUNDERFLOW,
- W_PDF_GROUPERROR,
- W_PDF_OPINVALIDINTEXT,
- W_PDF_NOTINCHARPROC,
- W_PDF_NESTEDTEXTBLOCK,
- W_PDF_ETNOTEXTBLOCK,
- W_PDF_TEXTOPNOBT,
- W_PDF_DEGENERATETM,
- W_PDF_BADICC_USE_ALT,
- W_PDF_BADICC_USECOMPS,
- W_PDF_BADTRSWITCH,
- W_PDF_BADSHADING,
- W_PDF_BADPATTERN,
- W_PDF_NONSTANDARD_OP,
- W_PDF_NUM_EXPONENT,
- W_PDF_STREAM_HAS_CONTENTS,
- W_PDF_STREAM_BAD_DECODEPARMS,
- W_PDF_MASK_ERROR,
- W_PDF_ANNOT_AP_ERROR,
- W_PDF_BAD_NAME_ESCAPE,
- W_PDF_TYPECHECK,
- W_PDF_BAD_TRAILER,
- W_PDF_ANNOT_ERROR,
- W_PDF_BAD_ICC_PROFILE_LINK,
- W_PDF_OVERFLOW_REAL,
- W_PDF_INVALID_REAL,
- W_PDF_DEVICEN_USES_ALL,
- W_PDF_BAD_MEDIABOX,
- W_PDF_MAX_WARNING /* Must be last entry, add new warnings immediately before this and update pdf_warning_strings in ghostpdf.c */
+#include "pdf_warnings.h"
+ W_PDF_MAX_WARNING /* last entry */
} pdf_warning;
#define PDF_ERROR_BYTE_SIZE ((E_PDF_MAX_ERROR - 1) / (sizeof(char) * 8) + 1)
@@ -132,12 +75,11 @@ typedef enum pdf_crypt_filter_e {
CRYPT_AESV3, /* 256-bit AES */
} pdf_crypt_filter;
-
-typedef enum pdf_overprint_control_e {
- PDF_OVERPRINT_ENABLE = 0,/* Default */
- PDF_OVERPRINT_DISABLE,
- PDF_OVERPRINT_SIMULATE
-} pdf_overprint_control_t;
+typedef enum pdf_type3_d_type_e {
+ pdf_type3_d_none,
+ pdf_type3_d0,
+ pdf_type3_d1
+} pdf_type3_d_type;
#define INITIAL_STACK_SIZE 32
#define MAX_STACK_SIZE 524288
@@ -188,6 +130,7 @@ typedef struct cmd_args_s {
bool dopdfmarks;
bool preserveannots;
char **preserveannottypes; /* Null terminated array of strings, NULL if none */
+ bool preservemarkedcontent;
bool nouserunit;
bool renderttnotdef;
bool pdfinfo;
@@ -196,11 +139,14 @@ typedef struct cmd_args_s {
bool ditherppi;
int PDFX3Profile_num;
char *UseOutputIntent;
- pdf_overprint_control_t overprint_control; /* Overprint -- enabled, disabled, simulated */
char *PageList;
bool QUIET;
bool verbose_errors;
bool verbose_warnings;
+ gs_string cidsubstpath;
+ gs_string cidsubstfont;
+ bool ignoretounicode;
+ bool nonativefontmap;
} cmd_args_t;
typedef struct encryption_state_s {
@@ -285,8 +231,14 @@ typedef struct text_state_s {
/* We need to know if we're in a type 3 CharProc which has executed a 'd1' operator.
* Colour operators are technically invalid if we are in a 'd1' context and we must
* ignore them.
+ * OSS-fuzz #45320 has a type 3 font with a BuildChar which has a 'RG' before the
+ * d1. This is (obviously) illegal because the spec says the first operation must
+ * be either a d0 or d1, in addition because of the graphics state depth hackery
+ * (see comments in pdf_d0() in pdf_font.c) this messes up the reference counting
+ * of the colour spaces, leading to a crash. So what was a boolean flag is now an
+ * enumerated type; pdf_type3_d_none, pdf_type3_d0 or pdf_type3_d1.
*/
- bool CharProc_is_d1;
+ pdf_type3_d_type CharProc_d_type;
/* If there is no current point when we do a BT we start by doing a 0 0 moveto in order
* to establish an initial point. However, this also starts a path. When we finish
* off with a BT we need to clear that path by doing a newpath, otherwise we might
@@ -342,6 +294,7 @@ typedef struct search_paths_s
typedef struct pdf_context_s
{
+ pdf_obj_common;
void *instance;
gs_memory_t *memory;
@@ -376,6 +329,7 @@ typedef struct pdf_context_s
/* Optional/Marked Content stuff */
void *OFFlevels;
uint64_t BMClevel;
+ bool BDCWasOC;
/* Bitfields recording whether any errors or warnings were encountered */
char pdf_errors[PDF_ERROR_BYTE_SIZE];
@@ -424,6 +378,9 @@ typedef struct pdf_context_s
/* Document level PDF objects */
xref_table_t *xref_table;
+ /* Warning! Do not use ctx->Trailer directly as it may be replaced if the file is repaired.
+ * See pdf_doc.c, pdf_read_Root()
+ */
pdf_dict *Trailer;
pdf_dict *Root;
pdf_dict *Info;
@@ -433,9 +390,6 @@ typedef struct pdf_context_s
pdf_dict *AcroForm;
bool NeedAppearances; /* From AcroForm, if any */
-
- /* Interpreter level PDF objects */
-
/* The interpreter operand stack */
uint32_t stack_size;
pdf_obj **stack_bot;
@@ -463,8 +417,13 @@ typedef struct pdf_context_s
/* A name table :-( */
pdfi_name_entry_t *name_table;
+ gs_string *fontmapfiles;
+ int num_fontmapfiles;
+
search_paths_t search_paths;
pdf_dict *pdffontmap;
+ pdf_dict *pdfnativefontmap; /* Explicit mappings take precedence, hence we need separate dictionaries */
+ pdf_dict *pdfcidfmap;
/* These function pointers can be replaced by ones intended to replicate
* PostScript functionality when running inside the Ghostscript PostScript
@@ -475,7 +434,7 @@ typedef struct pdf_context_s
int (*get_glyph_index)(gs_font *font, byte *str, uint size, uint *glyph);
#if REFCNT_DEBUG
- uint64_t UID;
+ uint64_t ref_UID;
#endif
#if CACHE_STATISTICS
uint64_t hits;
@@ -493,6 +452,7 @@ typedef struct pdf_context_s
int pdfi_add_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l, bool fontpath);
int pdfi_add_initial_paths_to_search_paths(pdf_context *ctx, const char *ppath, int l);
+int pdfi_add_fontmapfiles(pdf_context *ctx, const char *ppath, int l);
pdf_context *pdfi_create_context(gs_memory_t *pmem);
int pdfi_clear_context(pdf_context *ctx);
@@ -506,9 +466,10 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm);
int pdfi_process_pdf_file(pdf_context *ctx, char *filename);
int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_array);
int pdfi_close_pdf_file(pdf_context *ctx);
-void pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, void **saved_client_data, gs_gstate_client_procs *saved_procs);
-void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, void *client_data, const gs_gstate_client_procs *procs);
+int pdfi_gstate_from_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch, gsicc_profile_cache_t *profile_cache);
+void pdfi_gstate_to_PS(pdf_context *ctx, gs_gstate *pgs, pdfi_switch_t *i_switch);
+void pdfi_report_errors(pdf_context *ctx);
void pdfi_verbose_error(pdf_context *ctx, int gs_error, const char *gs_lib_function, int pdfi_error, const char *pdfi_function_name, const char *extra_info);
void pdfi_verbose_warning(pdf_context *ctx, int gs_error, const char *gs_lib_function, int pdfi_warning, const char *pdfi_function_name, const char *extra_info);
void pdfi_log_info(pdf_context *ctx, const char *pdfi_function, const char *info);
@@ -528,6 +489,10 @@ static inline void pdfi_set_warning(pdf_context *ctx, int gs_error, const char *
pdfi_verbose_warning(ctx, gs_error, gs_lib_function, pdfi_warning, pdfi_function_name, extra_info);
}
+/* Variants of the above that work in a printf style. */
+void pdfi_set_error_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_error pdfi_error, const char *pdfi_function_name, const char *fmt, ...);
+void pdfi_set_warning_var(pdf_context *ctx, int gs_error, const char *gs_lib_function, pdf_warning pdfi_warning, const char *pdfi_function_name, const char *fmt, ...);
+
#define PURGE_CACHE_PER_PAGE 0
#if PURGE_CACHE_PER_PAGE
diff --git a/pdf/pdf.mak b/pdf/pdf.mak
index ccb70916..7040a72e 100644
--- a/pdf/pdf.mak
+++ b/pdf/pdf.mak
@@ -1,4 +1,4 @@
-# Copyright (C) 2018-2021 Artifex Software, Inc.
+# Copyright (C) 2018-2022 Artifex Software, Inc.
# All Rights Reserved.
#
# This software is provided AS-IS with no warranty, either express or
@@ -60,7 +60,7 @@ PDFINCLUDES=$(PDFSRC)*.h $(GLGEN)arch.h $(strmio_h) $(stream_h) $(gsmatrix_h) $(
$(jpeglib__h) $(sdct_h) $(spdiffx_h)
$(PDFOBJ)ghostpdf.$(OBJ): $(PDFSRC)ghostpdf.c $(PDFINCLUDES) $(plmain_h) $(stream_h) $(strmio_h) \
- $(gsmchunk_h) $(PDF_MAK) $(MAKEDIRS)
+ $(gsmchunk_h) $(gsstate_h) $(gsicc_manage_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)ghostpdf.c $(PDFO_)ghostpdf.$(OBJ)
$(PDFOBJ)pdf_dict.$(OBJ): $(PDFSRC)pdf_dict.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
@@ -73,18 +73,18 @@ $(PDFOBJ)pdf_xref.$(OBJ): $(PDFSRC)pdf_xref.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDI
$(PDFCCC) $(PDFSRC)pdf_xref.c $(PDFO_)pdf_xref.$(OBJ)
$(PDFOBJ)pdf_fapi.$(OBJ): $(PDFSRC)pdf_fapi.c $(PDFINCLUDES) \
- $(memory__h) $(gsmemory_h) $(gserrors_h) $(gxdevice_h) $(gxfont_h) $(gxfcid_h) \
- $(gzstate_h) $(gxchar_h) $(gdebug_h) $(gxfapi_h) $(gscoord_h) $(gspath_h) $(gscencs_h) \
- $(gsagl_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(memory__h) $(gsmemory_h) $(gserrors_h) $(gxdevice_h) $(gxfont_h) $(gxfont0_h) \
+ $(gxfcid_h) $(gzstate_h) $(gxchar_h) $(gdebug_h) $(gxfapi_h) $(gscoord_h) \
+ $(gspath_h) $(gscencs_h) $(gsagl_h) $(gxfont1_h) $(gscrypt1_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_fapi.c $(PDFO_)pdf_fapi.$(OBJ)
$(PDFOBJ)pdf_font.$(OBJ): $(PDFSRC)pdf_font.c $(PDFINCLUDES) $(PDF_MAK) \
- $(gscencs_h) $(stream_h) $(strmio_h) $(MAKEDIRS)
+ $(gscencs_h) $(stream_h) $(strmio_h) $(gsstate_h) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font.c $(PDFO_)pdf_font.$(OBJ)
$(PDFOBJ)pdf_font0.$(OBJ): $(PDFSRC)pdf_font0.c $(PDFINCLUDES) $(PDF_MAK) \
- $(gxfont_h) $(gxfont0_h) $(MAKEDIRS)
+ $(gxfont_h) $(gxfont0_h) $(gsutil_h) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font0.c $(PDFO_)pdf_font0.$(OBJ)
$(PDFOBJ)pdf_ciddec.$(OBJ): $(PDFSRC)pdf_ciddec.c $(PDFINCLUDES) $(MAKEDIRS)
@@ -92,11 +92,12 @@ $(PDFOBJ)pdf_ciddec.$(OBJ): $(PDFSRC)pdf_ciddec.c $(PDFINCLUDES) $(MAKEDIRS)
$(PDFOBJ)pdf_font1.$(OBJ): $(PDFSRC)pdf_font1.c $(PDFINCLUDES) \
$(gsgdata_h) $(gstype1_h) $(gscencs_h) $(strmio_h) $(strimpl_h) $(stream_h) \
- $(sfilter_h) $(PDF_MAK) $(MAKEDIRS)
+ $(sfilter_h) $(gxtype1_h) $(gsutil_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font1.c $(PDFO_)pdf_font1.$(OBJ)
$(PDFOBJ)pdf_font1C.$(OBJ): $(PDFSRC)pdf_font1C.c $(PDFINCLUDES) \
$(gscedata_h) $(gscencs_h) $(gxfont0_h) $(gxfcid_h) \
+ $(gxtype1_h) $(gsutil_h) \
$(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font1C.c $(PDFO_)pdf_font1C.$(OBJ)
@@ -105,63 +106,66 @@ $(PDFOBJ)pdf_fontps.$(OBJ): $(PDFSRC)pdf_fontps.c $(PDFINCLUDES) \
$(PDFCCC) $(PDFSRC)pdf_fontps.c $(PDFO_)pdf_fontps.$(OBJ)
$(PDFOBJ)pdf_font3.$(OBJ): $(PDFSRC)pdf_font3.c $(PDFINCLUDES) \
- $(gscencs_h) $(gscedata_h) $(gsccode_h) $(gsuid_h) \
+ $(gscencs_h) $(gscedata_h) $(gsccode_h) $(gsuid_h) $(gsutil_h) \
$(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font3.c $(PDFO_)pdf_font3.$(OBJ)
$(PDFOBJ)pdf_fontTT.$(OBJ): $(PDFSRC)pdf_fontTT.c $(PDFINCLUDES) \
- $(gxfont42_h) $(gscencs_h) $(gsagl_h) $(PDF_MAK) $(MAKEDIRS)
+ $(gxfont42_h) $(gscencs_h) $(gsagl_h) $(gsutil_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_fontTT.c $(PDFO_)pdf_fontTT.$(OBJ)
$(PDFOBJ)pdf_font9.$(OBJ): $(PDFSRC)pdf_font9.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font9.c $(PDFO_)pdf_font9.$(OBJ)
$(PDFOBJ)pdf_font11.$(OBJ): $(PDFSRC)pdf_font11.c $(PDFINCLUDES) $(gxfont42_h) \
- $(gxfcid_h) $(PDF_MAK) $(MAKEDIRS)
+ $(gxfcid_h) $(gsutil_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_font11.c $(PDFO_)pdf_font11.$(OBJ)
$(PDFOBJ)pdf_cmap.$(OBJ): $(PDFSRC)pdf_cmap.c $(PDFINCLUDES) \
- $(strmio_h) $(stream_h) $(scanchar_h) $(PDF_MAK) $(MAKEDIRS)
+ $(strmio_h) $(stream_h) $(scanchar_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_cmap.c $(PDFO_)pdf_cmap.$(OBJ)
$(PDFOBJ)pdf_fmap.$(OBJ): $(PDFSRC)pdf_fmap.c $(PDFINCLUDES) \
- $(strmio_h) $(stream_h) $(scanchar_h) $(PDF_MAK) $(MAKEDIRS)
+ $(strmio_h) $(stream_h) $(scanchar_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_fmap.c $(PDFO_)pdf_fmap.$(OBJ)
$(PDFOBJ)pdf_text.$(OBJ): $(PDFSRC)pdf_text.c $(PDFINCLUDES) \
- $(gsstate_h) $(gsmatrix_h) $(gdevbbox_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(gsstate_h) $(gsmatrix_h) $(gdevbbox_h) $(gspaint_h) \
+ $(gscoord_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_text.c $(PDFO_)pdf_text.$(OBJ)
$(PDFOBJ)pdf_shading.$(OBJ): $(PDFSRC)pdf_shading.c $(PDFINCLUDES) \
- $(gxshade_h) $(gsptype2_h) $(gsfunc0_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(gsfunc3_h) $(gxshade_h) $(gsptype2_h) $(gsfunc0_h) \
+ $(gscolor3_h) $(gsstate_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_shading.c $(PDFO_)pdf_shading.$(OBJ)
$(PDFOBJ)pdf_func.$(OBJ): $(PDFSRC)pdf_func.c $(PDFINCLUDES) \
- $(gsdsrc_h) $(gsfunc0_h) $(gsfunc3_h) $(gsfunc4_h) $(stream_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(gsdsrc_h) $(gsfunc0_h) $(gsfunc3_h) $(gsfunc4_h) $(stream_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_func.c $(PDFO_)pdf_func.$(OBJ)
$(PDFOBJ)pdf_image.$(OBJ): $(PDFSRC)pdf_image.c $(PDFINCLUDES) \
- $(stream_h) $(gspath2_h) $(gsiparm4_h) $(gsiparm3_h) $(gsiparm3x_h) \
- $(gsform1_h) $(gstrans_h) \
+ $(stream_h) $(gsicc_cache_h) $(gspath2_h) $(gsiparm4_h) $(gsiparm3_h) $(gsiparm3x_h) \
+ $(gsform1_h) $(gstrans_h) $(gxdevsop_h) $(gspath_h) $(gsstate_h) $(gscoord_h) \
$(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_image.c $(PDFO_)pdf_image.$(OBJ)
-$(PDFOBJ)pdf_page.$(OBJ): $(PDFSRC)pdf_page.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_page.$(OBJ): $(PDFSRC)pdf_page.c $(PDFINCLUDES) \
+ $(gscoord_h) $(gspaint_h) $(gsstate_h) $(gspath2_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_page.c $(PDFO_)pdf_page.$(OBJ)
$(PDFOBJ)pdf_annot.$(OBJ): $(PDFSRC)pdf_annot.c $(PDFINCLUDES) $(gspath2_h) $(gxfarith_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(gxdevsop_h) $(gsstrtok_h) $(gscoord_h) $(gsline_h) $(gsutil_h) \
+ $(gspaint_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_annot.c $(PDFO_)pdf_annot.$(OBJ)
-$(PDFOBJ)pdf_mark.$(OBJ): $(PDFSRC)pdf_mark.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_mark.$(OBJ): $(PDFSRC)pdf_mark.c $(PDFINCLUDES) $(gscoord_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_mark.c $(PDFO_)pdf_mark.$(OBJ)
$(PDFOBJ)pdf_sec.$(OBJ): $(PDFSRC)pdf_sec.c $(PDFINCLUDES) \
- $(strmio_h) $(smd5_h) $(sarc4_h) $(aes_h) $(sha2_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(strmio_h) $(smd5_h) $(sarc4_h) $(aes_h) $(sha2_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_sec.c $(PDFO_)pdf_sec.$(OBJ)
$(PDFOBJ)pdf_utf8_mswin32_.$(OBJ): $(PDFSRC)pdf_utf8.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
@@ -182,72 +186,79 @@ $(PDFOBJ)pdf_utf8.$(OBJ): $(PDFOBJ)pdf_utf8_$(GSPLATFORM).$(OBJ) $(PDF_MAK) $(MA
$(PDFOBJ)pdf_stack.$(OBJ): $(PDFSRC)pdf_stack.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_stack.c $(PDFO_)pdf_stack.$(OBJ)
-$(PDFOBJ)pdf_gstate.$(OBJ): $(PDFSRC)pdf_gstate.c $(PDFINCLUDES) \
- $(gsmatrix_h) $(gslparam_h) $(gstparam_h) $(gxdht_h) $(gxht_h) $(gzht_h) $(gsht_h) \
- $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_gstate.$(OBJ): $(PDFSRC)pdf_gstate.c $(PDFINCLUDES) $(gsstate_h) \
+ $(gsmatrix_h) $(gslparam_h) $(gstparam_h) $(gxdht_h) $(gxht_h) $(gzht_h) $(gsht_h) \
+ $(gscoord_h) $(gsutil_h) $(gscolor3_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_gstate.c $(PDFO_)pdf_gstate.$(OBJ)
$(PDFOBJ)pdf_colour.$(OBJ): $(PDFSRC)pdf_colour.c $(PDFINCLUDES) \
- $(gsicc_manage_h) $(gsicc_create_h) $(gsptype2_h) $(gscsepr_h) \
- $(stream_h) $(strmio_h) $(gscdevn_h) $(gxcdevn_h) $(PDF_MAK) $(MAKEDIRS)
+ $(gsicc_manage_h) $(gsicc_profilecache_h) $(gsicc_create_h) $(gsicc_cache_h) $(gsptype2_h) $(gscsepr_h) \
+ $(stream_h) $(strmio_h) $(gscdevn_h) $(gxcdevn_h) $(gscolor_h) $(gsicc_h) $(gsstate_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_colour.c $(PDFO_)pdf_colour.$(OBJ)
$(PDFOBJ)pdf_pattern.$(OBJ): $(PDFSRC)pdf_pattern.c $(PDFINCLUDES) \
- $(gsicc_manage_h) $(gsicc_profilecache_h) $(gsicc_create_h) $(gscsepr_h) \
- $(stream_h) $(strmio_h) $(gscdevn_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(gsicc_manage_h) $(gsicc_profilecache_h) $(gsicc_create_h) $(gsptype2_h) \
+ $(gxdevsop_h) $(gscsepr_h) $(stream_h) $(strmio_h) $(gscdevn_h) $(gscoord_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_pattern.c $(PDFO_)pdf_pattern.$(OBJ)
-$(PDFOBJ)pdf_path.$(OBJ): $(PDFSRC)pdf_path.c $(PDFINCLUDES) $(gstypes_h) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_path.$(OBJ): $(PDFSRC)pdf_path.c $(PDFINCLUDES) $(gstypes_h) \
+ $(gspath_h) $(gspaint_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_path.c $(PDFO_)pdf_path.$(OBJ)
$(PDFOBJ)pdf_loop_detect.$(OBJ): $(PDFSRC)pdf_loop_detect.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_loop_detect.c $(PDFO_)pdf_loop_detect.$(OBJ)
$(PDFOBJ)pdf_int.$(OBJ): $(PDFSRC)pdf_int.c $(PDFINCLUDES) $(plmain_h) \
- $(stream_h) $(strmio_h) $(PDF_MAK) $(MAKEDIRS)
+ $(stream_h) $(strmio_h) $(gsgstate_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_int.c $(PDFO_)pdf_int.$(OBJ)
$(PDFOBJ)pdf_file_luratech.$(OBJ): $(PDFSRC)pdf_file.c $(sjpeg_h) $(stream_h) $(strimpl_h) \
- $(strmio_h) $(gpmisc_h) $(simscale_h) $(szlibx_h) $(spngx_h) $(spdiffx_h) $(slzw_h) $(sstring_h) \
- $(sa85d_h) $(scfx_h) $(srlx_h) $(jpeglib__h) $(sdct_h) $(sjpeg_h) $(sfilter_h) $(sarc4_h) \
- $(saes_h) $(ssha2_h) $(sjbig2_luratech_h) $(sjpx_luratech_h) \
+ $(strmio_h) $(gpmisc_h) $(simscale_h) $(szlibx_h) $(spngx_h) $(spdiffx_h) $(slzw_h) \
+ $(sstring_h) $(sa85d_h) $(scfx_h) $(srlx_h) $(jpeglib__h) $(sdct_h) $(sjpeg_h) \
+ $(sfilter_h) $(sarc4_h) $(saes_h) $(ssha2_h) $(gxdevsop_h) \
+ $(sjbig2_luratech_h) $(sjpx_luratech_h) \
$(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFLURCC) $(PDFSRC)pdf_file.c $(PDFO_)pdf_file_luratech.$(OBJ)
$(PDFOBJ)pdf_file_jbig2dec.$(OBJ): $(PDFSRC)pdf_file.c $(sjpeg_h) $(stream_h) $(strimpl_h) \
- $(strmio_h) $(simscale_h) $(szlibx_h) $(spngx_h) $(spdiffx_h) $(slzw_h) $(sstring_h) \
- $(sa85d_h) $(scfx_h) $(srlx_h) $(jpeglib__h) $(sdct_h) $(sjpeg_h) $(sfilter_h) $(sarc4_h) \
- $(saes_h) $(ssha2_h) $(sjbig2_h) $(sjpx_openjpeg_h) \
+ $(strmio_h) $(gpmisc_h) $(simscale_h) $(szlibx_h) $(spngx_h) $(spdiffx_h) $(slzw_h) \
+ $(sstring_h) $(sa85d_h) $(scfx_h) $(srlx_h) $(jpeglib__h) $(sdct_h) $(sjpeg_h) \
+ $(sfilter_h) $(sarc4_h) $(saes_h) $(ssha2_h) $(gxdevsop_h) \
+ $(sjpx_openjpeg_h) \
$(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFJB2CC) $(PDFSRC)pdf_file.c $(PDFO_)pdf_file_jbig2dec.$(OBJ)
$(PDFOBJ)pdf_file.$(OBJ): $(PDFOBJ)pdf_file_$(JBIG2_LIB).$(OBJ)
$(CP_) $(PDFOBJ)pdf_file_$(JBIG2_LIB).$(OBJ) $(PDFOBJ)pdf_file.$(OBJ)
-$(PDFOBJ)pdf_trans.$(OBJ): $(PDFSRC)pdf_trans.c $(PDFINCLUDES) $(gstparam_h) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_trans.$(OBJ): $(PDFSRC)pdf_trans.c $(PDFINCLUDES) $(gstparam_h) \
+ $(gsicc_manage_h) $(gscoord_h) $(gsstate_h) $(gspath_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_trans.c $(PDFO_)pdf_trans.$(OBJ)
-$(PDFOBJ)pdf_device.$(OBJ): $(PDFSRC)pdf_device.c $(PDFINCLUDES) $(gdevvec_h) \
- $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_device.$(OBJ): $(PDFSRC)pdf_device.c $(PDFINCLUDES) $(gsdevice_h) $(gspaint_h) \
+ $(gdevvec_h) $(gxdevsop_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_device.c $(PDFO_)pdf_device.$(OBJ)
-$(PDFOBJ)pdf_misc.$(OBJ): $(PDFSRC)pdf_misc.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_misc.$(OBJ): $(PDFSRC)pdf_misc.c $(PDFINCLUDES) $(gspath_h) $(gspaint_h) \
+ $(gsicc_manage_h) $(gsstate_h) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_misc.c $(PDFO_)pdf_misc.$(OBJ)
$(PDFOBJ)pdf_optcontent.$(OBJ): $(PDFSRC)pdf_optcontent.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_optcontent.c $(PDFO_)pdf_optcontent.$(OBJ)
-$(PDFOBJ)pdf_check.$(OBJ): $(PDFSRC)pdf_check.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
+$(PDFOBJ)pdf_check.$(OBJ): $(PDFSRC)pdf_check.c $(PDFINCLUDES) $(gsdevice_h) $(gspaint_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_check.c $(PDFO_)pdf_check.$(OBJ)
$(PDFOBJ)pdf_deref.$(OBJ): $(PDFSRC)pdf_deref.c $(PDFINCLUDES) $(strmio_h) $(stream_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_deref.c $(PDFO_)pdf_deref.$(OBJ)
$(PDFOBJ)pdf_repair.$(OBJ): $(PDFSRC)pdf_repair.c $(PDFINCLUDES) \
- $(strmio_h) $(stream_h) \
- $(PDF_MAK) $(MAKEDIRS)
+ $(strmio_h) $(stream_h) \
+ $(PDF_MAK) $(MAKEDIRS)
$(PDFCCC) $(PDFSRC)pdf_repair.c $(PDFO_)pdf_repair.$(OBJ)
$(PDFOBJ)pdf_obj.$(OBJ): $(PDFSRC)pdf_obj.c $(PDFINCLUDES) $(PDF_MAK) $(MAKEDIRS)
diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 116081c2..7b96be1c 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.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
@@ -24,6 +24,7 @@
#include "pdf_loop_detect.h"
#include "pdf_colour.h"
#include "pdf_trans.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_misc.h"
#include "pdf_optcontent.h"
@@ -1076,8 +1077,7 @@ pdfi_annot_display_formatted_text(pdf_context *ctx, pdf_dict *annot,
code = pdfi_string_bbox(ctx, temp_string, &bbox, &awidth, false);
if (code < 0) goto exit;
- if (linestart || ((x + awidth.x) <= x_max)) {
- } else {
+ if (!linestart && ((x + awidth.x) > x_max)) {
x = x_start;
linestart = true;
}
@@ -1447,8 +1447,8 @@ static int pdfi_annot_draw_LE_one(pdf_context *ctx, pdf_dict *annot, pdf_name *L
}
if (!dispatch_ptr->name) {
char str[100];
- memcpy(str, (const char *)LE->data, LE->length);
- str[LE->length] = '\0';
+ memcpy(str, (const char *)LE->data, LE->length < 100 ? LE->length : 99);
+ str[LE->length < 100 ? LE->length : 99] = '\0';
dbgmprintf1(ctx->memory, "ANNOT: WARNING No handler for LE %s\n", str);
}
@@ -3091,6 +3091,11 @@ static int pdfi_annot_draw_PolyLine(pdf_context *ctx, pdf_dict *annot, pdf_obj *
code = pdfi_dict_knownget_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
if (code < 0) goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_undefined);
+ goto exit;
+ }
+
size = pdfi_array_size(Vertices);
if (size == 0) {
code = 0;
@@ -3155,7 +3160,7 @@ static int pdfi_annot_draw_Polygon(pdf_context *ctx, pdf_dict *annot, pdf_obj *N
if (code < 0) goto exit1;
code = pdfi_dict_knownget_type(ctx, annot, "Vertices", PDF_ARRAY, (pdf_obj **)&Vertices);
- if (code < 0) goto exit;
+ if (code <= 0) goto exit;
code = pdfi_annot_path_array(ctx, annot, Vertices);
if (code < 0) goto exit1;
@@ -3708,8 +3713,8 @@ static int pdfi_annot_draw_NotImplemented(pdf_context *ctx, pdf_dict *annot, pdf
code = pdfi_dict_get_type(ctx, annot, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
if (code < 0) goto exit;
- memcpy(str, (const char *)Subtype->data, Subtype->length);
- str[Subtype->length] = '\0';
+ memcpy(str, (const char *)Subtype->data, Subtype->length < 100 ? Subtype->length : 99);
+ str[Subtype->length < 100 ? Subtype->length : 99] = '\0';
dbgmprintf1(ctx->memory, "ANNOT: No AP, default appearance for Subtype %s Not Implemented\n", str);
exit:
@@ -3880,8 +3885,8 @@ static int pdfi_annot_draw(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
}
if (!dispatch_ptr->subtype) {
char str[100];
- memcpy(str, (const char *)subtype->data, subtype->length);
- str[subtype->length] = '\0';
+ memcpy(str, (const char *)subtype->data, subtype->length < 100 ? subtype->length : 99);
+ str[subtype->length < 100 ? subtype->length : 99] = '\0';
dbgmprintf1(ctx->memory, "ANNOT: No handler for subtype %s\n", str);
/* Not necessarily an error? We can just render the AP if there is one */
@@ -4107,6 +4112,117 @@ static int pdfi_annot_preserve_modAP(pdf_context *ctx, pdf_dict *annot, pdf_name
/* Make a temporary copy of the annotation dict with some fields left out or
* modified, then do a pdfmark on it
*/
+
+const char *PermittedKeys[] = {
+ /* These keys are valid for all annotation types, we specifically do not allow /P or /Parent */
+ "Type",
+ "Subtype",
+ "Rect",
+ "Contents",
+ "NM",
+ "M",
+ "F",
+ "AP",
+ "AS",
+ "Border",
+ "C",
+ "StructParent",
+ "OC",
+ "AF",
+ "ca",
+ "CA",
+ "BM",
+ "Lang",
+ /* Keys by annotation type (some are common to more than one type, only one entry per key) */
+ /* Markup Annotations we specifically do not permit RT, IRT or Popup */
+ "T",
+ "RC",
+ "CreationDate",
+ "Subj",
+ "IT",
+ "ExData",
+ /* Text annotations */
+ "Open",
+ "Name",
+ "State",
+ "StateModel",
+ /* This isn't specified as being allowed, but Acrobat does something with it, so we need to preserve it */
+ "Rotate",
+ /* Link annotations */
+ "A",
+ "Dest",
+ "H",
+ "PA",
+ "QuadPoints",
+ /* FreeText annotations */
+ "DA",
+ "Q",
+ "DS",
+ "CL",
+ "IT",
+ "BE",
+ "RD",
+ "BS",
+ "LE",
+ /* Line Annotations */
+ "L",
+ "LE",
+ "IC",
+ "LL",
+ "LLE",
+ "Cap",
+ "LLO",
+ "CP",
+ "Measure",
+ "CO",
+ /* Square and Circle annotations */
+ "Path",
+ /* Polygon and PolyLine annotations */
+ "Vertices",
+ /* Text Markup annotations */
+ /* Caret annotations */
+ "Sy",
+ /* Rubber Stamp annotations */
+ /* Ink annotations */
+ "InkList",
+ /* Popup annotations */
+ "Open",
+ /* File attachment annotation */
+ "FS",
+ /* Sound annotations */
+ "Sound",
+ /* Movie annotations */
+ "Movie",
+ /* Screen annotations */
+ "MK",
+ "AA",
+ /* We don't handle Widget annotations as annotations, we draw them */
+ /* Printer's Mark annotations */
+ /* Trap Network annotations */
+ /* Watermark annotations */
+ "FixedPrint",
+ "Matrix",
+ "H",
+ "V",
+ /* Redaction annotations */
+ "RO",
+ "OverlayText",
+ "Repeat",
+ /* Projection annotations */
+ /* 3D and RichMedia annotations */
+};
+
+static int isKnownKey(pdf_context *ctx, pdf_name *Key)
+{
+ int i = 0;
+
+ for (i = 0; i < sizeof(PermittedKeys) / sizeof (const char *); i++) {
+ if (pdfi_name_is(Key, PermittedKeys[i]))
+ return 1;
+ }
+ return 0;
+}
+
static int pdfi_annot_preserve_mark(pdf_context *ctx, pdf_dict *annot, pdf_name *subtype)
{
int code = 0;
@@ -4136,51 +4252,44 @@ static int pdfi_annot_preserve_mark(pdf_context *ctx, pdf_dict *annot, pdf_name
while (code >= 0) {
resolve = false;
- if (pdfi_name_is(Key, "Popup") || pdfi_name_is(Key, "IRT") || pdfi_name_is(Key, "RT") ||
- pdfi_name_is(Key, "P") || pdfi_name_is(Key, "Parent")) {
- /* Delete some keys
- * These would not be handled correctly and are optional.
- * (see pdf_draw.ps/loadannot())
- * TODO: Could probably handle some of these since they are typically
- * just references, and we do have a way to handle references?
- * Look into it later...
- */
+ if (!isKnownKey(ctx, Key)) {
code = pdfi_dict_delete_pair(ctx, tempdict, Key);
if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "AP")) {
- /* Special handling for AP -- have fun! */
- code = pdfi_annot_preserve_modAP(ctx, tempdict, Key);
- if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "QuadPoints")) {
- code = pdfi_annot_preserve_modQP(ctx, tempdict, Key);
- if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "A")) {
- code = pdfi_mark_modA(ctx, tempdict);
- if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "Dest")) {
- if (ctx->args.no_pdfmark_dests) {
- /* If omitting dests, such as for multi-page output, then omit this whole annotation */
- code = 0;
- goto exit;
- }
- code = pdfi_mark_modDest(ctx, tempdict);
- if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "StructTreeRoot")) {
- /* TODO: Bug691785 has Link annots with /StructTreeRoot
- * It is super-circular, and causes issues.
- * GS code only adds in certain values for Link so it doesn't
- * run into a problem. I am just going to delete it.
- * There should be a better solution to handle circular stuff
- * generically.
- */
- code = pdfi_dict_delete_pair(ctx, tempdict, Key);
- if (code < 0) goto exit;
- } else if (pdfi_name_is(Key, "Sound") || pdfi_name_is(Key, "Movie")) {
- resolve = false;
} else {
- resolve = true;
+ if (pdfi_name_is(Key, "AP")) {
+ /* Special handling for AP -- have fun! */
+ code = pdfi_annot_preserve_modAP(ctx, tempdict, Key);
+ if (code < 0) goto exit;
+ } else if (pdfi_name_is(Key, "QuadPoints")) {
+ code = pdfi_annot_preserve_modQP(ctx, tempdict, Key);
+ if (code < 0) goto exit;
+ } else if (pdfi_name_is(Key, "A")) {
+ code = pdfi_pdfmark_modA(ctx, tempdict);
+ if (code < 0) goto exit;
+ } else if (pdfi_name_is(Key, "Dest")) {
+ if (ctx->args.no_pdfmark_dests) {
+ /* If omitting dests, such as for multi-page output, then omit this whole annotation */
+ code = 0;
+ goto exit;
+ }
+ code = pdfi_pdfmark_modDest(ctx, tempdict);
+ if (code < 0) goto exit;
+ } else if (pdfi_name_is(Key, "StructTreeRoot")) {
+ /* TODO: Bug691785 has Link annots with /StructTreeRoot
+ * It is super-circular, and causes issues.
+ * GS code only adds in certain values for Link so it doesn't
+ * run into a problem. I am just going to delete it.
+ * There should be a better solution to handle circular stuff
+ * generically.
+ */
+ code = pdfi_dict_delete_pair(ctx, tempdict, Key);
+ if (code < 0) goto exit;
+ } else if (pdfi_name_is(Key, "Sound") || pdfi_name_is(Key, "Movie")) {
+ resolve = false;
+ } else {
+ resolve = true;
+ }
}
-
if (resolve) {
code = pdfi_dict_get_by_key(ctx, annot, (const pdf_name *)Key, &Value);
if (code < 0) goto exit;
@@ -4212,9 +4321,9 @@ static int pdfi_annot_preserve_mark(pdf_context *ctx, pdf_dict *annot, pdf_name
gs_currentmatrix(ctx->pgs, &ctm);
if (pdfi_name_is(subtype, "Link"))
- code = pdfi_mark_from_dict(ctx, tempdict, &ctm, "LNK");
+ code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "LNK");
else
- code = pdfi_mark_from_dict(ctx, tempdict, &ctm, "ANN");
+ code = pdfi_pdfmark_from_dict(ctx, tempdict, &ctm, "ANN");
if (code < 0) goto exit;
exit:
diff --git a/pdf/pdf_array.c b/pdf/pdf_array.c
index 07a90812..5f269fe5 100644
--- a/pdf/pdf_array.c
+++ b/pdf/pdf_array.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -53,7 +53,7 @@ int pdfi_array_alloc(pdf_context *ctx, uint64_t size, pdf_array **a)
/* Make a null object */
code = pdfi_object_alloc(ctx, PDF_NULL, 1, &n);
if (code < 0) {
- pdfi_countdown(*a);
+ pdfi_free_object((pdf_obj *)(*a));
*a = NULL;
return code;
}
@@ -121,7 +121,7 @@ int pdfi_array_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indi
/* Fetch object from array, resolving indirect reference if needed
* setref -- indicates whether to replace indirect ref with the object
*/
-static int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref)
+int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache)
{
int code;
pdf_obj *obj;
@@ -139,7 +139,13 @@ static int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_
pdf_obj *o1 = NULL;
pdf_indirect_ref *r = (pdf_indirect_ref *)obj;
- code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, &o1);
+ if (r->ref_object_num == a->object_num)
+ return_error(gs_error_circular_reference);
+
+ if (cache)
+ code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, &o1);
+ else
+ code = pdfi_deref_loop_detect_nocache(ctx, r->ref_object_num, r->ref_generation_num, &o1);
if (code < 0)
return code;
@@ -154,19 +160,6 @@ static int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_
return 0;
}
-/* The object returned by pdfi_array_get has its reference count incremented by 1 to
- * indicate the reference now held by the caller, in **o.
- */
-int pdfi_array_get(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
-{
- int code;
-
- code = pdfi_array_fetch(ctx, a, index, o, true);
- if (code < 0) return code;
-
- return 0;
-}
-
/* Get element from array without resolving PDF_INDIRECT dereferences.
* It looks to me like some usages need to do the checking themselves to
* avoid circular references? Can remove this if not really needed.
@@ -190,7 +183,7 @@ int pdfi_array_get_no_store_R(pdf_context *ctx, pdf_array *a, uint64_t index, pd
{
int code;
- code = pdfi_array_fetch(ctx, a, index, o, false);
+ code = pdfi_array_fetch(ctx, a, index, o, false, false);
if (code < 0) return code;
return 0;
@@ -267,7 +260,7 @@ bool pdfi_array_known(pdf_context *ctx, pdf_array *a, pdf_obj *o, int *index)
pdf_obj *val;
int code;
- code = pdfi_array_fetch(ctx, a, i, &val, true);
+ code = pdfi_array_fetch(ctx, a, i, &val, true, true);
if (code < 0)
continue;
if (val->object_num == o->object_num) {
diff --git a/pdf/pdf_array.h b/pdf/pdf_array.h
index f118737e..37097aaa 100644
--- a/pdf/pdf_array.h
+++ b/pdf/pdf_array.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -20,12 +20,25 @@
static inline uint64_t pdfi_array_size(pdf_array *a) { return a->size; }
+int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache);
+/* The object returned by pdfi_array_get has its reference count incremented by 1 to
+ * indicate the reference now held by the caller, in **o.
+ */
+static int inline pdfi_array_get(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
+{
+ return pdfi_array_fetch(ctx, a, index, o, true, true);
+}
+
+static int inline pdfi_array_get_nocache(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
+{
+ return pdfi_array_fetch(ctx, a, index, o, true, false);
+}
+
void pdfi_free_array(pdf_obj *o);
int pdfi_array_alloc(pdf_context *ctx, uint64_t size, pdf_array **a);
int pdfi_array_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen);
int pdfi_array_get_no_deref(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o);
int pdfi_array_get_no_store_R(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o);
-int pdfi_array_get(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o);
int pdfi_array_get_type(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj_type t, pdf_obj **o);
int pdfi_array_get_int(pdf_context *ctx, pdf_array *a, uint64_t index, int64_t *i);
int pdfi_array_get_number(pdf_context *ctx, pdf_array *a, uint64_t index, double *f);
diff --git a/pdf/pdf_check.c b/pdf/pdf_check.c
index 13d974cb..00933bdf 100644
--- a/pdf/pdf_check.c
+++ b/pdf/pdf_check.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
@@ -24,10 +24,12 @@
#include "pdf_loop_detect.h"
#include "pdf_colour.h"
#include "pdf_trans.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_misc.h"
#include "pdf_check.h"
#include "pdf_device.h"
+#include "gsdevice.h" /* For gs_setdevice_no_erase */
#include "gspaint.h" /* For gs_erasepage() */
/* For performance and resource reasons we do not want to install the transparency blending
@@ -133,7 +135,8 @@ pdfi_check_init_tracker(pdf_context *ctx, pdfi_check_tracker_t *tracker)
memset(tracker->CheckedResources, 0x00, tracker->size);
- if (ctx->device_state.spot_capable || ctx->args.overprint_control == PDF_OVERPRINT_SIMULATE) {
+ if (ctx->device_state.spot_capable ||
+ (ctx->pgs->device->icc_struct->overprint_control) == gs_overprint_control_simulate) {
code = pdfi_dict_alloc(ctx, 32, &tracker->spot_dict);
if (code < 0)
goto cleanup;
@@ -1143,6 +1146,8 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
*/
pdfi_device_set_flags(ctx);
code = pdfi_check_init_tracker(ctx, &tracker);
+ if (code < 0)
+ goto exit;
/* Check for spots and transparency in this page */
code = pdfi_check_page_inner(ctx, page_dict, &tracker);
@@ -1156,20 +1161,88 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
/* If setup requested, tell the device about spots and transparency */
if (do_setup) {
gs_c_param_list list;
+ int a = 0;
+ pdf_name *Key = NULL;
+ pdf_obj *Value = NULL;
+ uint64_t index = 0;
gs_c_param_list_write(&list, ctx->memory);
/* If there are spot colours (and by inference, the device renders spot plates) then
* send the number of Spots to the device, so it can setup correctly.
*/
- if (tracker.spot_dict)
- param_write_int((gs_param_list *)&list, "PageSpotColors", &spots);
+ if (tracker.spot_dict) {
+ /* There is some awkwardness here. If the SeparationColorNames setting
+ * fails, we want to ignore it (this can mean that we exceeded the maximum
+ * number of colourants and some will be converted to CMYK). But if that happens,
+ * any other parameters in the same list which haven't already been prcoessed
+ * will be lost. So we need to send two lists, the SeparationColorNames and
+ * 'everything else'.
+ */
+ if (spots > 0) {
+ gs_param_string_array sa;
+ gs_param_string *table = NULL;
+
+ table = (gs_param_string *)gs_alloc_byte_array(ctx->memory, spots, sizeof(gs_param_string), "SeparationNames");
+ if (table != NULL)
+ {
+ memset(table, 0x00, spots * sizeof(gs_param_string));
+
+ code = pdfi_dict_first(ctx, tracker.spot_dict, (pdf_obj **)&Key, &Value, &index);
+ while (code >= 0)
+ {
+ if (Key->type == PDF_NAME) {
+ table[a].data = ((pdf_string *)Key)->data;
+ table[a].size = ((pdf_string *)Key)->length;
+ table[a++].persistent = false;
+ }
+ /* Although we count down the returned PDF objects here, the pointers
+ * to the name data remain valid and won't move. Provided we don't
+ * retain the pointers after we free the tracker dictionary this is
+ * safe to do.
+ */
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ code = pdfi_dict_next(ctx, tracker.spot_dict, (pdf_obj **)&Key, &Value, &index);
+ }
+ sa.data = table;
+ sa.size = spots;
+ sa.persistent = false;
+
+ (void)param_write_string_array((gs_param_list *)&list, "SeparationColorNames", &sa);
+ gs_c_param_list_read(&list);
+ code = gs_putdeviceparams(ctx->pgs->device, (gs_param_list *)&list);
+ gs_c_param_list_release(&list);
- code = param_write_bool((gs_param_list *)&list, "PageUsesTransparency",
- &tracker.transparent);
+ gs_free_object(ctx->memory, table, "SeparationNames");
+ if (code > 0) {
+ /* The device was closed, we need to reopen it */
+ code = gs_setdevice_no_erase(ctx->pgs, ctx->pgs->device);
+ if (code < 0)
+ goto exit;
+ gs_erasepage(ctx->pgs);
+ }
+
+ /* Reset the list back to being writeable */
+ gs_c_param_list_write(&list, ctx->memory);
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ goto exit;
+ }
+ }
+ /* Update the number of spots */
+ param_write_int((gs_param_list *)&list, "PageSpotColors", &spots);
+ }
+ /* Update the page transparency */
+ (void)param_write_bool((gs_param_list *)&list, "PageUsesTransparency",
+ &tracker.transparent);
gs_c_param_list_read(&list);
code = gs_putdeviceparams(ctx->pgs->device, (gs_param_list *)&list);
gs_c_param_list_release(&list);
+
if (code > 0) {
/* The device was closed, we need to reopen it */
code = gs_setdevice_no_erase(ctx->pgs, ctx->pgs->device);
@@ -1180,10 +1253,15 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
}
/* Set our values in the context, for caller */
- ctx->page.has_transparency = tracker.transparent;
+ if (!ctx->args.notransparency)
+ ctx->page.has_transparency = tracker.transparent;
ctx->page.num_spots = spots;
ctx->page.has_OP = tracker.has_overprint;
+ /* High level devices do not render overprint */
+ if (ctx->device_state.HighLevelDevice)
+ ctx->page.has_OP = false;
+
exit:
(void)pdfi_check_free_tracker(ctx, &tracker);
return code;
diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c
index fcf363ff..d7198e24 100644
--- a/pdf/pdf_cmap.c
+++ b/pdf/pdf_cmap.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -33,6 +33,7 @@ static int cmap_usecmap_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte
pdf_cmap *pdficmap = (pdf_cmap *)s->client_data;
pdf_name *n = NULL;
pdf_cmap *upcmap = NULL;
+ int code = 0;
if (pdf_ps_stack_count(s) < 1)
return_error(gs_error_stackunderflow);
@@ -40,7 +41,7 @@ static int cmap_usecmap_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte
/* If we've already got some definitions, ignore the usecmap op */
if (pdficmap->code_space.num_ranges == 0) {
byte *nstr = NULL;
- int code, len = s->cur[0].size;
+ int len = s->cur[0].size;
if (pdf_ps_obj_has_type(&(s->cur[0]), PDF_PS_OBJ_NAME)) {
nstr = s->cur[0].val.name;
@@ -49,9 +50,10 @@ static int cmap_usecmap_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte
nstr = s->cur[0].val.string;
}
else {
- return_error(gs_error_typecheck);
+ code = gs_note_error(gs_error_typecheck);
}
- code = pdfi_name_alloc(pdficmap->ctx, nstr, len, (pdf_obj **)&n);
+ if (code >= 0)
+ code = pdfi_name_alloc(pdficmap->ctx, nstr, len, (pdf_obj **)&n);
if (code >= 0) {
pdfi_countup(n);
code = pdfi_read_cmap(pdficmap->ctx, (pdf_obj *)n, &upcmap);
@@ -77,10 +79,13 @@ static int cmap_usecmap_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte
}
}
}
-
}
pdfi_countdown(upcmap);
pdfi_countdown(n);
+ if (code < 0) {
+ (void)pdf_ps_stack_pop(s, 1);
+ return code;
+ }
return pdf_ps_stack_pop(s, 1);
}
@@ -103,23 +108,38 @@ static int cmap_endcodespacerange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *
/* increment to_pop to cover the mark object */
numranges = to_pop++;
while (numranges % 2) numranges--;
+ if (numranges > 200) {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_syntaxerror);
+ }
- if (numranges > 0 && pdf_ps_obj_has_type(&(s->cur[0]), PDF_PS_OBJ_STRING) &&
- pdf_ps_obj_has_type(&(s->cur[-1]), PDF_PS_OBJ_STRING)) {
+ if (numranges > 0
+ && pdf_ps_obj_has_type(&(s->cur[0]), PDF_PS_OBJ_STRING) && s->cur[0].size <= MAX_CMAP_CODE_SIZE
+ && pdf_ps_obj_has_type(&(s->cur[-1]), PDF_PS_OBJ_STRING) && s->cur[-1].size <= MAX_CMAP_CODE_SIZE) {
code_space->num_ranges += numranges >> 1;
code_space->ranges = (gx_code_space_range_t *)gs_alloc_byte_array(mem, code_space->num_ranges,
sizeof(gx_code_space_range_t), "cmap_endcodespacerange_func(ranges)");
- if (nr > 0) {
- memcpy(code_space->ranges, gcsr, nr);
- gs_free_object(mem, gcsr, "cmap_endcodespacerange_func(gcsr");
- }
+ if (code_space->ranges != NULL) {
+ if (nr > 0) {
+ memcpy(code_space->ranges, gcsr, nr);
+ gs_free_object(mem, gcsr, "cmap_endcodespacerange_func(gcsr");
+ }
- for (i = nr; i < code_space->num_ranges; i++) {
- memcpy(code_space->ranges[i].first, s->cur[-((i * 2) + 1)].val.string, s->cur[-((i * 2) + 1)].size);
- memcpy(code_space->ranges[i].last, s->cur[-(i * 2)].val.string, s->cur[-(i * 2)].size);
- code_space->ranges[i].size = s->cur[-(i * 2)].size;
+ for (i = nr; i < code_space->num_ranges; i++) {
+ int si = i - nr;
+ int s1 = s->cur[-((si * 2) + 1)].size < MAX_CMAP_CODE_SIZE ? s->cur[-((si * 2) + 1)].size : MAX_CMAP_CODE_SIZE;
+ int s2 = s->cur[-(si * 2)].size < MAX_CMAP_CODE_SIZE ? s->cur[-(si * 2)].size : MAX_CMAP_CODE_SIZE;
+
+ memcpy(code_space->ranges[i].first, s->cur[-((si * 2) + 1)].val.string, s1);
+ memcpy(code_space->ranges[i].last, s->cur[-(si * 2)].val.string, s2);
+ code_space->ranges[i].size = s->cur[-(si * 2)].size;
+ }
+ }
+ else {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_VMerror);
}
}
return pdf_ps_stack_pop(s, to_pop);
@@ -151,6 +171,10 @@ static int general_endcidrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, pdf_cmap
* startcode, endcode and basecid
*/
while (ncodemaps % 3) ncodemaps--;
+ if (ncodemaps > 300) {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_syntaxerror);
+ }
stobj = &s->cur[-ncodemaps] + 1;
@@ -173,6 +197,12 @@ static int general_endcidrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, pdf_cmap
preflen = 1;
}
+ if (preflen > MAX_CMAP_CODE_SIZE || stobj[i].size - preflen > MAX_CMAP_CODE_SIZE || stobj[i + 1].size - preflen > MAX_CMAP_CODE_SIZE
+ || stobj[i].size - preflen < 0 || stobj[i + 1].size - preflen < 0) {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_syntaxerror);
+ }
+
/* Find how many bytes we need for the cidbase value */
/* We always store at least two bytes for the cidbase value */
for (valuelen = 16; valuelen < 32 && (cidbase >> valuelen) > 0; valuelen += 1)
@@ -214,7 +244,8 @@ static int general_endcidrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, pdf_cmap
if (cmap_insert_map(cmap_range, pdfir) < 0) break;
}
else {
- break;
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_VMerror);
}
}
}
@@ -247,6 +278,11 @@ static int cmap_endfbrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, by
*/
while (ncodemaps % 3) ncodemaps--;
+ if (ncodemaps > 300) {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_syntaxerror);
+ }
+
stobj = &s->cur[-ncodemaps] + 1;
for (i = 0; i < ncodemaps; i += 3) {
/* Lazy: to make the loop below simpler, put single
@@ -256,6 +292,7 @@ static int cmap_endfbrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, by
pdf_ps_stack_object_t *arr;
arr = (pdf_ps_stack_object_t *) gs_alloc_bytes(mem, sizeof(pdf_ps_stack_object_t), "cmap_endfbrange_func(pdf_ps_stack_object_t");
if (arr == NULL) {
+ (void)pdf_ps_stack_pop(s, to_pop);
return_error(gs_error_VMerror);
}
else {
@@ -355,7 +392,8 @@ static int cmap_endfbrange_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, by
if (cmap_insert_map(&(pdficmap->cmap_range), pdfir) < 0) break;
}
else {
- break;
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_VMerror);
}
}
}
@@ -377,6 +415,11 @@ static int general_endcidchar_func(gs_memory_t *mem, pdf_ps_ctx_t *s, pdf_cmap *
*/
while (ncodemaps % 2) ncodemaps--;
+ if (ncodemaps > 200) {
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_syntaxerror);
+ }
+
stobj = &s->cur[-ncodemaps] + 1;
for (i = 0; i < ncodemaps; i += 2) {
@@ -428,7 +471,8 @@ static int general_endcidchar_func(gs_memory_t *mem, pdf_ps_ctx_t *s, pdf_cmap *
if (cmap_insert_map(cmap_range, pdfir) < 0) break;
}
else {
- break;
+ (void)pdf_ps_stack_pop(s, to_pop);
+ return_error(gs_error_VMerror);
}
}
}
@@ -454,6 +498,11 @@ static int cmap_endbfchar_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byt
pdf_ps_stack_object_t *stobj;
int i, j;
+ if (ncodemaps > 200) {
+ (void)pdf_ps_stack_pop(s, ncodemaps);
+ return_error(gs_error_syntaxerror);
+ }
+
stobj = &s->cur[-ncodemaps] + 1;
for (i = 0; i < ncodemaps; i += 2) {
@@ -554,7 +603,7 @@ static int cmap_def_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *buf
pdficmap->cmaptype = s->cur[0].val.i;
}
else {
- pdficmap->type = 1;
+ pdficmap->cmaptype = 1;
}
}
else if (!memcmp(s->cur[-1].val.name, CMAP_NAME_AND_LEN("XUID"))) {
@@ -638,6 +687,9 @@ pdf_cmap_open_file(pdf_context *ctx, gs_string *cmap_name, byte **buf, int64_t *
const char *path_pfx = "CMap/";
fname[0] = '\0';
+ if (strlen(path_pfx) + cmap_name->size >= gp_file_name_sizeof)
+ return_error(gs_error_rangecheck);
+
strncat(fname, path_pfx, strlen(path_pfx));
strncat(fname, (char *)cmap_name->data, cmap_name->size);
code = pdfi_open_resource_file(ctx, (const char *)fname, (const int)strlen(fname), &s);
@@ -831,6 +883,9 @@ pdfi_read_cmap(pdf_context *ctx, pdf_obj *cmap, pdf_cmap **pcmap)
}
}
}
+ else {
+ goto error_out;
+ }
return 0;
error_out:
diff --git a/pdf/pdf_colour.c b/pdf/pdf_colour.c
index e6061db1..dcc3ebf0 100644
--- a/pdf/pdf_colour.c
+++ b/pdf/pdf_colour.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -24,9 +24,12 @@
#include "pdf_misc.h"
#include "gsicc_manage.h"
#include "gsicc_profilecache.h"
+#include "gsicc_cache.h"
+
#include "gsicc_create.h"
#include "gsptype2.h"
+
#include "pdf_file.h"
#include "pdf_dict.h"
#include "pdf_loop_detect.h"
@@ -189,7 +192,7 @@ static int pdfi_check_for_spots_by_array(pdf_context *ctx, pdf_array *color_arra
if (code < 0)
goto exit;
- code = pdfi_dict_put_obj(ctx, spot_dict, name, dummy);
+ code = pdfi_dict_put_obj(ctx, spot_dict, name, dummy, true);
pdfi_countdown(name);
if (code < 0)
break;
@@ -216,7 +219,7 @@ static int pdfi_check_for_spots_by_array(pdf_context *ctx, pdf_array *color_arra
if (code < 0)
goto exit;
- code = pdfi_dict_put_obj(ctx, spot_dict, (pdf_obj *)space, dummy);
+ code = pdfi_dict_put_obj(ctx, spot_dict, (pdf_obj *)space, dummy, true);
goto exit;
} else {
code = pdfi_find_resource(ctx, (unsigned char *)"ColorSpace",
@@ -305,9 +308,15 @@ int pdfi_ri(pdf_context *ctx)
static void pdfi_cspace_free_callback(gs_memory_t * mem, void *cs)
{
gs_color_space *pcs = (gs_color_space *)cs;
- pdf_context *ctx = (pdf_context *)pcs->interpreter_data;
+ pdf_obj *o = (pdf_obj *)pcs->interpreter_data;
+ pdf_context *ctx = NULL;
gs_function_t *pfn;
+ if (o == NULL)
+ return;
+
+ ctx = o->ctx;
+
if (gs_color_space_get_index(pcs) == gs_color_space_index_Separation) {
/* Handle cleanup of Separation functions if applicable */
pfn = gs_cspace_get_sepr_function(pcs);
@@ -321,6 +330,10 @@ static void pdfi_cspace_free_callback(gs_memory_t * mem, void *cs)
if (pfn)
pdfi_free_function(ctx, pfn);
}
+ if (o->type != PDF_CTX) {
+ pdfi_countdown(o);
+ pcs->interpreter_data = NULL;
+ }
}
int pdfi_gs_setgray(pdf_context *ctx, double d)
@@ -328,7 +341,7 @@ int pdfi_gs_setgray(pdf_context *ctx, double d)
int code = 0;
/* PDF Reference 1.7 p423, any colour operators in a CharProc, following a d1, should be ignored */
- if (ctx->text.inside_CharProc && ctx->text.CharProc_is_d1)
+ if (ctx->text.inside_CharProc && ctx->text.CharProc_d_type != pdf_type3_d0)
return 0;
if (ctx->page.DefaultGray_cs != NULL) {
@@ -337,15 +350,15 @@ int pdfi_gs_setgray(pdf_context *ctx, double d)
code = gs_setcolorspace(ctx->pgs, ctx->page.DefaultGray_cs);
if (code < 0)
return code;
- pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, NULL);
cc.paint.values[0] = d;
+ cc.pattern = 0;
return gs_setcolor(ctx->pgs, &cc);
} else {
code = gs_setgray(ctx->pgs, d);
if (code < 0)
return code;
- pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
}
+ pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
return 0;
}
@@ -354,7 +367,7 @@ int pdfi_gs_setrgbcolor(pdf_context *ctx, double r, double g, double b)
int code = 0;
/* PDF Reference 1.7 p423, any colour operators in a CharProc, following a d1, should be ignored */
- if (ctx->text.inside_CharProc && ctx->text.CharProc_is_d1)
+ if (ctx->text.inside_CharProc && ctx->text.CharProc_d_type != pdf_type3_d0)
return 0;
if (ctx->page.DefaultRGB_cs != NULL) {
@@ -367,6 +380,7 @@ int pdfi_gs_setrgbcolor(pdf_context *ctx, double r, double g, double b)
cc.paint.values[0] = r;
cc.paint.values[1] = g;
cc.paint.values[2] = b;
+ cc.pattern = 0;
return gs_setcolor(ctx->pgs, &cc);
} else {
code = gs_setrgbcolor(ctx->pgs, r, g, b);
@@ -382,7 +396,7 @@ static int pdfi_gs_setcmykcolor(pdf_context *ctx, double c, double m, double y,
int code = 0;
/* PDF Reference 1.7 p423, any colour operators in a CharProc, following a d1, should be ignored */
- if (ctx->text.inside_CharProc && ctx->text.CharProc_is_d1)
+ if (ctx->text.inside_CharProc && ctx->text.CharProc_d_type != pdf_type3_d0)
return 0;
if (ctx->page.DefaultCMYK_cs != NULL) {
@@ -391,18 +405,18 @@ static int pdfi_gs_setcmykcolor(pdf_context *ctx, double c, double m, double y,
code = gs_setcolorspace(ctx->pgs, ctx->page.DefaultCMYK_cs);
if (code < 0)
return code;
- pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, NULL);
cc.paint.values[0] = c;
cc.paint.values[1] = m;
cc.paint.values[2] = y;
cc.paint.values[3] = k;
+ cc.pattern = 0;
return gs_setcolor(ctx->pgs, &cc);
} else {
code = gs_setcmykcolor(ctx->pgs, c, m, y, k);
if (code < 0)
return code;
- pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
}
+ pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
return 0;
}
@@ -413,7 +427,7 @@ int pdfi_gs_setcolorspace(pdf_context *ctx, gs_color_space *pcs)
*/
if (ctx->pgs->color[0].color_space->id != pcs->id) {
/* PDF Reference 1.7 p423, any colour operators in a CharProc, following a d1, should be ignored */
- if (ctx->text.inside_CharProc && ctx->text.CharProc_is_d1)
+ if (ctx->text.inside_CharProc && ctx->text.CharProc_d_type != pdf_type3_d0)
return 0;
pdfi_set_colour_callback(pcs, ctx, pdfi_cspace_free_callback);
@@ -699,9 +713,14 @@ int pdfi_setstrokecolor(pdf_context *ctx)
int ncomps, code;
gs_client_color cc;
+ cc.pattern = 0;
gs_swapcolors_quick(ctx->pgs);
pcs = gs_currentcolorspace(ctx->pgs);
ncomps = cs_num_components(pcs);
+ if (ncomps < 1) {
+ gs_swapcolors_quick(ctx->pgs);
+ return_error(gs_error_syntaxerror);
+ }
code = pdfi_get_color_from_stack(ctx, &cc, ncomps);
if (code == 0) {
code = gs_setcolor(ctx->pgs, &cc);
@@ -716,7 +735,10 @@ int pdfi_setfillcolor(pdf_context *ctx)
int ncomps, code;
gs_client_color cc;
+ cc.pattern = 0;
ncomps = cs_num_components(pcs);
+ if (ncomps < 1)
+ return_error(gs_error_syntaxerror);
code = pdfi_get_color_from_stack(ctx, &cc, ncomps);
if (code == 0) {
code = gs_setcolor(ctx->pgs, &cc);
@@ -750,16 +772,18 @@ pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, boo
if (pdfi_count_stack(ctx) < 1) {
code = gs_note_error(gs_error_stackunderflow);
- goto cleanupExit;
+ goto cleanupExit1;
}
+ memset(&cc, 0x00, sizeof(gs_client_color));
+
if (pcs->type == &gs_color_space_type_Pattern)
is_pattern = true;
if (is_pattern) {
if (ctx->stack_top[-1]->type != PDF_NAME) {
pdfi_clearstack(ctx);
code = gs_note_error(gs_error_syntaxerror);
- goto cleanupExit;
+ goto cleanupExit0;
}
base_space = pcs->base_space;
code = pdfi_pattern_set(ctx, stream_dict, page_dict, (pdf_name *)ctx->stack_top[-1], &cc);
@@ -768,23 +792,27 @@ pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, boo
/* Ignore the pattern if we failed to set it */
pdfi_set_warning(ctx, 0, NULL, W_PDF_BADPATTERN, "pdfi_setcolorN", (char *)"PATTERN: Error setting pattern");
code = 0;
- goto cleanupExit;
+ goto cleanupExit1;
}
if (base_space && pattern_instance_uses_base_space(cc.pattern))
ncomps = cs_num_components(base_space);
else
ncomps = 0;
- } else {
+ } else
ncomps = cs_num_components(pcs);
- cc.pattern = NULL;
- }
- if (ncomps > 0)
+ if (ncomps > 0) {
code = pdfi_get_color_from_stack(ctx, &cc, ncomps);
- if (code < 0)
- goto cleanupExit;
+ if (code < 0)
+ goto cleanupExit1;
+ }
if (pcs->type == &gs_color_space_type_Indexed) {
+ if (ncomps <= 0)
+ {
+ code = gs_note_error(gs_error_rangecheck);
+ goto cleanupExit1;
+ }
if (cc.paint.values[0] < 0)
cc.paint.values[0] = 0.0;
else
@@ -806,6 +834,7 @@ pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, boo
code = gs_setcolor(ctx->pgs, &cc);
+cleanupExit1:
if (is_pattern)
/* cc is a local scope variable, holding a reference to a pattern.
* We need to count the refrence down before the variable goes out of scope
@@ -813,7 +842,7 @@ pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, boo
*/
rc_decrement(cc.pattern, "pdfi_setcolorN");
-cleanupExit:
+cleanupExit0:
if (!is_fill)
gs_swapcolors_quick(ctx->pgs);
return code;
@@ -824,7 +853,7 @@ cleanupExit:
/* Starting with the ICCBased colour space */
/* This routine is mostly a copy of seticc() in zicc.c */
-static int pdfi_create_icc(pdf_context *ctx, char *Name, stream *s, int ncomps, int *icc_N, float *range_buff, gs_color_space **ppcs)
+static int pdfi_create_icc(pdf_context *ctx, char *Name, stream *s, int ncomps, int *icc_N, float *range_buff, ulong dictkey, gs_color_space **ppcs)
{
int code, k;
gs_color_space * pcs;
@@ -981,13 +1010,16 @@ static int pdfi_create_icc(pdf_context *ctx, char *Name, stream *s, int ncomps,
rc_adjust(picc_profile, -2, "pdfi_create_icc");
rc_increment(pcs->cmm_icc_profile_data);
}
+ /* Add the color space to the profile cache */
+ if (dictkey != 0)
+ gsicc_add_cs(ctx->pgs, pcs, dictkey);
if (ppcs!= NULL){
*ppcs = pcs;
pdfi_set_colour_callback(pcs, ctx, pdfi_cspace_free_callback);
} else {
code = pdfi_gs_setcolorspace(ctx, pcs);
- rc_decrement_only_cs(pcs, "pdfi_seticc_cal");
+ rc_decrement_only_cs(pcs, "pdfi_create_icc");
}
/* The context has taken a reference to the colorspace. We no longer need
@@ -1003,6 +1035,34 @@ static int pdfi_create_iccprofile(pdf_context *ctx, pdf_stream *ICC_obj, char *c
byte *profile_buffer;
gs_offset_t savedoffset;
int code, code1;
+ ulong dictkey = 0;
+
+ /* See if the color space is in the profile cache */
+ /* NOTE! 0 indicates a named colour space for JPX images, do not attempt to
+ * find a cached space for this. Conveniently should we somehow manage to get
+ * here from an array or other object which is not an indirect reference then we will
+ * again not attempt to cache the space or lookup the cache.
+ */
+ if (!gs_currentoverrideicc(ctx->pgs)) {
+ if (ICC_obj->object_num != 0) {
+ gs_color_space *pcs = NULL;
+
+ pcs = gsicc_find_cs(ICC_obj->object_num, ctx->pgs);
+ if (pcs != NULL) {
+ if (ppcs!= NULL){
+ *ppcs = pcs;
+ } else {
+ code = pdfi_gs_setcolorspace(ctx, pcs);
+ rc_decrement_only_cs(pcs, "pdfi_create_iccprofile");
+ }
+ *icc_N = gs_color_space_num_components(pcs);
+ /* We're passing back a new reference, increment the count */
+ rc_adjust_only(pcs, 1, "pdfi_create_iccprofile, return cached ICC profile");
+ return 0;
+ }
+ dictkey = ICC_obj->object_num;
+ }
+ }
/* Save the current stream position, and move to the start of the profile stream */
savedoffset = pdfi_tell(ctx->main_stream);
@@ -1022,7 +1082,7 @@ static int pdfi_create_iccprofile(pdf_context *ctx, pdf_stream *ICC_obj, char *c
}
/* Now, finally, we can call the code to create and set the profile */
- code = pdfi_create_icc(ctx, cname, profile_stream->s, (int)N, icc_N, range, ppcs);
+ code = pdfi_create_icc(ctx, cname, profile_stream->s, (int)N, icc_N, range, dictkey, ppcs);
code1 = pdfi_close_memory_stream(ctx, profile_buffer, profile_stream);
@@ -1059,6 +1119,10 @@ static int pdfi_create_iccbased(pdf_context *ctx, pdf_array *color_array, int in
code = pdfi_dict_get_int(ctx, dict, "N", &N);
if (code < 0)
goto done;
+ if (N != 1 && N != 3 && N != 4) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto done;
+ }
code = pdfi_dict_knownget(ctx, dict, "Name", &Name);
if (code > 0) {
if(Name->type == PDF_STRING || Name->type == PDF_NAME) {
@@ -1186,8 +1250,11 @@ static int pdfi_create_iccbased(pdf_context *ctx, pdf_array *color_array, int in
break;
}
}
- if (ppcs!= NULL)
+ if (ppcs!= NULL) {
*ppcs = pcs;
+ if (pcs != NULL)
+ pdfi_set_colour_callback(pcs, ctx, pdfi_cspace_free_callback);
+ }
else {
if (pcs != NULL) {
code = pdfi_gs_setcolorspace(ctx, pcs);
@@ -1351,6 +1418,7 @@ pdfi_seticc_cal(pdf_context *ctx, float *white, float *black, float *gamma,
if (ppcs!= NULL){
*ppcs = pcs;
+ pdfi_set_colour_callback(pcs, ctx, pdfi_cspace_free_callback);
} else {
code = pdfi_gs_setcolorspace(ctx, pcs);
rc_decrement_only_cs(pcs, "pdfi_seticc_cal");
@@ -1404,7 +1472,7 @@ static int pdfi_create_CalGray(pdf_context *ctx, pdf_array *color_array, int ind
goto exit;
}
- if (pdfi_dict_knownget_type(ctx, CalGray_dict, "BlackPoint", PDF_ARRAY, (pdf_obj **)&PDFArray)) {
+ if (pdfi_dict_knownget_type(ctx, CalGray_dict, "BlackPoint", PDF_ARRAY, (pdf_obj **)&PDFArray) > 0) {
if (pdfi_array_size(PDFArray) != 3){
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -1426,7 +1494,7 @@ static int pdfi_create_CalGray(pdf_context *ctx, pdf_array *color_array, int ind
PDFArray = NULL;
}
- if (pdfi_dict_knownget_number(ctx, CalGray_dict, "Gamma", &f))
+ if (pdfi_dict_knownget_number(ctx, CalGray_dict, "Gamma", &f) > 0)
Gamma = (float)f;
/* The PDF 1.7 reference states that Gamma
* (if present) must be positive.
@@ -1487,7 +1555,7 @@ static int pdfi_create_CalRGB(pdf_context *ctx, pdf_array *color_array, int inde
goto exit;
}
- if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "BlackPoint", PDF_ARRAY, (pdf_obj **)&PDFArray)) {
+ if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "BlackPoint", PDF_ARRAY, (pdf_obj **)&PDFArray) > 0) {
if (pdfi_array_size(PDFArray) != 3){
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -1509,7 +1577,7 @@ static int pdfi_create_CalRGB(pdf_context *ctx, pdf_array *color_array, int inde
PDFArray = NULL;
}
- if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "Gamma", PDF_ARRAY, (pdf_obj **)&PDFArray)) {
+ if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "Gamma", PDF_ARRAY, (pdf_obj **)&PDFArray) > 0) {
if (pdfi_array_size(PDFArray) != 3){
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -1524,7 +1592,7 @@ static int pdfi_create_CalRGB(pdf_context *ctx, pdf_array *color_array, int inde
PDFArray = NULL;
}
- if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&PDFArray)) {
+ if (pdfi_dict_knownget_type(ctx, CalRGB_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&PDFArray) > 0) {
if (pdfi_array_size(PDFArray) != 9){
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -1603,6 +1671,7 @@ static int pdfi_create_Separation(pdf_context *ctx, pdf_array *color_array, int
goto pdfi_separation_error;
rc_decrement(pcs_alt, "pdfi_create_Separation");
+ pcs_alt = NULL;
pcs->params.separation.mem = ctx->memory;
pcs->params.separation.sep_type = sep_type;
pcs->params.separation.sep_name = (char *)gs_alloc_bytes(ctx->memory->non_gc_memory, name->length + 1, "pdfi_setseparationspace(ink)");
@@ -1621,6 +1690,7 @@ static int pdfi_create_Separation(pdf_context *ctx, pdf_array *color_array, int
*/
code = pdfi_gs_setcolorspace(ctx, pcs);
*ppcs = pcs;
+ pdfi_set_colour_callback(pcs, ctx, pdfi_cspace_free_callback);
} else {
code = pdfi_gs_setcolorspace(ctx, pcs);
/* release reference from construction */
@@ -1754,10 +1824,12 @@ all_error:
if (o->type == PDF_ARRAY) {
ArrayAlternate = (pdf_array *)o;
code = pdfi_create_colorspace_by_array(ctx, ArrayAlternate, 0, stream_dict, page_dict, &pcs_alt, inline_image);
- if (code < 0) {
- pdfi_countdown(o);
+ if (code < 0)
+ /* OSS-fuzz error 42973; we don't need to count down 'o' here because
+ * we have assigned it to ArrayAlternate and both the success and error
+ * paths count down ArrayAlternate.
+ */
goto pdfi_devicen_error;
- }
}
else {
code = gs_error_typecheck;
@@ -2066,7 +2138,7 @@ pdfi_create_indexed(pdf_context *ctx, pdf_array *color_array, int index,
num_values = (hival+1) * cs_num_components(pcs_base);
if (num_values > lookup_length) {
- dmprintf2(ctx->memory, "WARNING: pdfi_create_indexed() got %ld values, expected at least %d values\n",
+ dmprintf2(ctx->memory, "WARNING: pdfi_create_indexed() got %"PRIi64" values, expected at least %d values\n",
lookup_length, num_values);
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -2201,7 +2273,7 @@ static int pdfi_create_JPX_space(pdf_context *ctx, const char *name, int num_com
int code, icc_N;
float range_buff[6] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
- code = pdfi_create_icc(ctx, (char *)name, NULL, num_components, &icc_N, range_buff, ppcs);
+ code = pdfi_create_icc(ctx, (char *)name, NULL, num_components, &icc_N, range_buff, 0, ppcs);
return code;
}
@@ -2272,7 +2344,10 @@ pdfi_create_colorspace_by_array(pdf_context *ctx, pdf_array *color_array, int in
} else if (pdfi_name_is(space, "Separation")) {
code = pdfi_create_Separation(ctx, color_array, index, stream_dict, page_dict, ppcs, inline_image);
} else {
- code = pdfi_find_resource(ctx, (unsigned char *)"ColorSpace",
+ if (stream_dict == NULL)
+ code = gs_note_error(gs_error_syntaxerror);
+ else
+ code = pdfi_find_resource(ctx, (unsigned char *)"ColorSpace",
space, (pdf_dict *)stream_dict, page_dict, (pdf_obj **)&a);
if (code < 0)
goto exit;
@@ -2332,13 +2407,32 @@ pdfi_create_colorspace_by_name(pdf_context *ctx, pdf_name *name,
code = pdfi_create_JPX_space(ctx, "sgray", 1, ppcs);
} else {
pdf_obj *ref_space = NULL;
+
+ if (ppcs == NULL && check_same_current_space(ctx, name) == 1)
+ return 0;
+
code = pdfi_find_resource(ctx, (unsigned char *)"ColorSpace", name, (pdf_dict *)stream_dict,
page_dict, &ref_space);
if (code < 0)
return code;
+ if (ref_space->type == PDF_NAME) {
+ if (ref_space->object_num != 0 && ref_space->object_num == name->object_num) {
+ pdfi_countdown(ref_space);
+ return_error(gs_error_circular_reference);
+ }
+ }
+
/* recursion */
code = pdfi_create_colorspace(ctx, ref_space, stream_dict, page_dict, ppcs, inline_image);
+
+ if (code >= 0) {
+ if (ppcs != NULL)
+ pdfi_set_colourspace_name(ctx, *ppcs, name);
+ else
+ pdfi_set_colourspace_name(ctx, ctx->pgs->color[0].color_space, name);
+ }
+
pdfi_countdown(ref_space);
return code;
}
@@ -2357,7 +2451,7 @@ pdfi_create_colorspace_by_name(pdf_context *ctx, pdf_name *name,
*/
int
pdfi_create_icc_colorspace_from_stream(pdf_context *ctx, pdf_c_stream *stream, gs_offset_t offset,
- unsigned int length, int comps, int *icc_N, gs_color_space **ppcs)
+ unsigned int length, int comps, int *icc_N, ulong dictkey, gs_color_space **ppcs)
{
pdf_c_stream *profile_stream = NULL;
byte *profile_buffer;
@@ -2380,7 +2474,7 @@ pdfi_create_icc_colorspace_from_stream(pdf_context *ctx, pdf_c_stream *stream, g
}
/* Now, finally, we can call the code to create and set the profile */
- code = pdfi_create_icc(ctx, NULL, profile_stream->s, comps, icc_N, range, ppcs);
+ code = pdfi_create_icc(ctx, NULL, profile_stream->s, comps, icc_N, range, dictkey, ppcs);
code1 = pdfi_close_memory_stream(ctx, profile_buffer, profile_stream);
@@ -2408,7 +2502,7 @@ int pdfi_create_colorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_di
return_error(gs_error_typecheck);
}
}
- if (ppcs && *ppcs && code >= 0)
+ if (code >= 0 && ppcs && *ppcs)
(void)(*ppcs)->type->install_cspace(*ppcs, ctx->pgs);
(void)pdfi_loop_detector_cleartomark(ctx);
@@ -2569,32 +2663,47 @@ static int pdfi_device_setoutputintent(pdf_context *ctx, pdf_dict *profile_dict,
Finally, we will use the output intent profile for the default profile
of the proper Device profile in the icc manager, again, unless someone
has explicitly set this default profile.
+
+ All of this is skipped if we are forcing oveprint simulation with
+ the output intent set, in which case we will push the pdf14 device
+ to render directly to the the output intent color space and then
+ do a final transform to the target color space.
*/
dev_comps = dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]->num_comps;
index = gsicc_get_default_type(dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]);
- if (ncomps == dev_comps && index < gs_color_space_index_DevicePixel) {
- /* The OI profile is the same type as the profile for the device and a
- "default" profile for the device was not externally set. So we go
- ahead and use the OI profile as the device profile. Care needs to be
- taken here to keep from screwing up any device parameters. We will
- use a keyword of OIProfile for the user/device parameter to indicate
- its usage. Also, note conflicts if one is setting object dependent
- color management */
- dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE] = picc_profile;
- rc_increment(picc_profile);
- if_debug0m(gs_debug_flag_icc, ctx->memory, "[icc] OutputIntent used for device profile\n");
- } else {
- if (dev_profile->proof_profile == NULL) {
- /* This means that we should use the OI profile as the proofing
- profile. Note that if someone already has specified a
- proofing profile it is unclear what they are trying to do
- with the output intent. In this case, we will use it
- just for the source data below */
- dev_profile->proof_profile = picc_profile;
+
+ /* If we are doing simulate overprint and the output intent is different than
+ what the device profile is the we will end up pushing the pdf14 device
+ and doing a rendering to the output intent color space. Keep the device
+ profile as is, and do not do a proofing profile */
+
+ if (!(ctx->pgs->device->icc_struct->overprint_control == gs_overprint_control_simulate &&
+ !gsicc_profiles_equal(dev_profile->oi_profile, dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE]))) {
+ if (ncomps == dev_comps && index < gs_color_space_index_DevicePixel) {
+ /* The OI profile is the same type as the profile for the device and a
+ "default" profile for the device was not externally set. So we go
+ ahead and use the OI profile as the device profile. Care needs to be
+ taken here to keep from screwing up any device parameters. We will
+ use a keyword of OIProfile for the user/device parameter to indicate
+ its usage. Also, note conflicts if one is setting object dependent
+ color management */
+ dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE] = picc_profile;
rc_increment(picc_profile);
- if_debug0m(gs_debug_flag_icc, ctx->memory, "[icc] OutputIntent used for proof profile\n");
+ if_debug0m(gs_debug_flag_icc, ctx->memory, "[icc] OutputIntent used for device profile\n");
+ } else {
+ if (dev_profile->proof_profile == NULL) {
+ /* This means that we should use the OI profile as the proofing
+ profile. Note that if someone already has specified a
+ proofing profile it is unclear what they are trying to do
+ with the output intent. In this case, we will use it
+ just for the source data below */
+ dev_profile->proof_profile = picc_profile;
+ rc_increment(picc_profile);
+ if_debug0m(gs_debug_flag_icc, ctx->memory, "[icc] OutputIntent used for proof profile\n");
+ }
}
}
+
/* Now the source colors. See which source color space needs to use the
output intent ICC profile */
index = gsicc_get_default_type(source_profile);
@@ -2674,3 +2783,171 @@ int pdfi_color_setoutputintent(pdf_context *ctx, pdf_dict *intent_dict, pdf_stre
pdfi_seek(ctx, ctx->main_stream, savedoffset, SEEK_SET);
return code;
}
+
+static int Check_Default_Space(pdf_context *ctx, pdf_obj *space, pdf_dict *source_dict, int num_components)
+{
+ pdf_obj *primary = NULL;
+ pdf_obj *ref_space = NULL;
+ int code = 0;
+
+ if (space->type == PDF_NAME)
+ {
+ if (pdfi_name_is((const pdf_name *)space, "DeviceGray"))
+ return (num_components == 1 ? 0 : gs_error_rangecheck);
+ if (pdfi_name_is((const pdf_name *)space, "DeviceCMYK"))
+ return (num_components == 4 ? 0 : gs_error_rangecheck);
+ if (pdfi_name_is((const pdf_name *)space, "DeviceRGB"))
+ return (num_components == 3 ? 0 : gs_error_rangecheck);
+
+ code = pdfi_find_resource(ctx, (unsigned char *)"ColorSpace", (pdf_name *)space, (pdf_dict *)source_dict,
+ NULL, &ref_space);
+ if (code < 0)
+ return code;
+
+ if (ref_space->type == PDF_NAME) {
+ if (ref_space->object_num != 0 && ref_space->object_num == space->object_num) {
+ pdfi_countdown(ref_space);
+ return_error(gs_error_circular_reference);
+ }
+ if (pdfi_name_is((const pdf_name *)ref_space, "DeviceGray")) {
+ pdfi_countdown(ref_space);
+ return (num_components == 1 ? 0 : gs_error_rangecheck);
+ }
+ if (pdfi_name_is((const pdf_name *)ref_space, "DeviceCMYK")) {
+ pdfi_countdown(ref_space);
+ return (num_components == 4 ? 0 : gs_error_rangecheck);
+ }
+ if (pdfi_name_is((const pdf_name *)ref_space, "DeviceRGB")) {
+ pdfi_countdown(ref_space);
+ return (num_components == 3 ? 0 : gs_error_rangecheck);
+ }
+ pdfi_countdown(ref_space);
+ return_error(gs_error_typecheck);
+ }
+ space = ref_space;
+ }
+
+ if (space->type == PDF_ARRAY) {
+ code = pdfi_array_get(ctx, (pdf_array *)space, 0, &primary);
+ if (code < 0)
+ goto exit;
+
+ if (primary->type == PDF_NAME) {
+ if (pdfi_name_is((pdf_name *)primary, "Lab")) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ if (pdfi_name_is((pdf_name *)primary, "Pattern")) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ if (pdfi_name_is((pdf_name *)primary, "Indexed")) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ }
+ } else
+ code = gs_note_error(gs_error_typecheck);
+
+exit:
+ pdfi_countdown(primary);
+ pdfi_countdown(ref_space);
+ return code;
+}
+
+int pdfi_setup_DefaultSpaces(pdf_context *ctx, pdf_dict *source_dict)
+{
+ int code = 0;
+ pdf_dict *resources_dict = NULL, *colorspaces_dict = NULL;
+ pdf_obj *DefaultSpace = NULL;
+
+ if (ctx->args.NOSUBSTDEVICECOLORS)
+ return 0;
+
+ /* Create any required DefaultGray, DefaultRGB or DefaultCMYK
+ * spaces.
+ */
+ code = pdfi_dict_knownget(ctx, source_dict, "Resources", (pdf_obj **)&resources_dict);
+ if (code > 0) {
+ code = pdfi_dict_knownget(ctx, resources_dict, "ColorSpace", (pdf_obj **)&colorspaces_dict);
+ if (code > 0) {
+ code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultGray", &DefaultSpace);
+ if (code > 0) {
+ gs_color_space *pcs;
+
+ code = Check_Default_Space(ctx, DefaultSpace, source_dict, 1);
+ if (code >= 0) {
+ code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, source_dict, &pcs, false);
+ /* If any given Default* space fails simply ignore it, we wil then use the Device
+ * space instead, this is as per the spec.
+ */
+ if (code >= 0) {
+ if (gs_color_space_num_components(pcs) == 1) {
+ ctx->page.DefaultGray_cs = pcs;
+ pdfi_set_colour_callback(pcs, ctx, NULL);
+ } else {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ rc_decrement(pcs, "setup_DefautSpaces");
+ }
+ }
+ } else
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ }
+ pdfi_countdown(DefaultSpace);
+ DefaultSpace = NULL;
+ code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultRGB", &DefaultSpace);
+ if (code > 0) {
+ gs_color_space *pcs;
+
+ code = Check_Default_Space(ctx, DefaultSpace, source_dict, 1);
+ if (code >= 0) {
+ code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, source_dict, &pcs, false);
+ /* If any given Default* space fails simply ignore it, we wil then use the Device
+ * space instead, this is as per the spec.
+ */
+ if (code >= 0) {
+ if (gs_color_space_num_components(pcs) == 3) {
+ ctx->page.DefaultRGB_cs = pcs;
+ pdfi_set_colour_callback(pcs, ctx, NULL);
+ } else {
+ rc_decrement(pcs, "setup_DefautSpaces");
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ }
+ }
+ } else
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ }
+ pdfi_countdown(DefaultSpace);
+ DefaultSpace = NULL;
+ code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultCMYK", &DefaultSpace);
+ if (code > 0) {
+ gs_color_space *pcs;
+
+ code = Check_Default_Space(ctx, DefaultSpace, source_dict, 1);
+ if (code >= 0) {
+ code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, source_dict, &pcs, false);
+ /* If any given Default* space fails simply ignore it, we wil then use the Device
+ * space instead, this is as per the spec.
+ */
+ if (code >= 0) {
+ if (gs_color_space_num_components(pcs) == 4) {
+ ctx->page.DefaultCMYK_cs = pcs;
+ pdfi_set_colour_callback(pcs, ctx, NULL);
+ } else {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ rc_decrement(pcs, "setup_DefautSpaces");
+ }
+ }
+ } else
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DEFAULTSPACE, "pdfi_setup_DefaultSpaces", NULL);
+ }
+ pdfi_countdown(DefaultSpace);
+ DefaultSpace = NULL;
+ }
+ }
+
+ pdfi_countdown(DefaultSpace);
+ pdfi_countdown(resources_dict);
+ pdfi_countdown(colorspaces_dict);
+ return 0;
+}
diff --git a/pdf/pdf_colour.h b/pdf/pdf_colour.h
index 5cc9f0eb..263c3d9d 100644
--- a/pdf/pdf_colour.h
+++ b/pdf/pdf_colour.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -20,13 +20,49 @@
#include "gscolor1.h"
#include "gscspace.h"
+#include "pdf_stack.h" /* for pdfi_countup/countdown */
+#include "pdf_misc.h" /* for pdf_name_cmp */
+
+static inline void pdfi_set_colourspace_name(pdf_context *ctx, gs_color_space *pcs, pdf_name *n)
+{
+ if (pcs->interpreter_data != NULL) {
+ pdf_obj *o = (pdf_obj *)(pcs->interpreter_data);
+ if (o != NULL && o->type == PDF_NAME) {
+ pdfi_countdown(o);
+ pcs->interpreter_data = NULL;
+ }
+ }
+
+ if (n != NULL) {
+ pcs->interpreter_data = n;
+ pdfi_countup(n);
+ } else {
+ if (pcs->interpreter_data == NULL)
+ pcs->interpreter_data = ctx;
+ }
+}
static inline void pdfi_set_colour_callback(gs_color_space *pcs, pdf_context *ctx, gs_cspace_free_proc_t pdfi_cspace_free_callback)
{
- pcs->interpreter_data = ctx;
+ if (pcs->interpreter_data == NULL)
+ pcs->interpreter_data = ctx;
pcs->interpreter_free_cspace_proc = pdfi_cspace_free_callback;
}
+static inline int check_same_current_space(pdf_context *ctx, pdf_name *n)
+{
+ pdf_obj *o = (pdf_obj *)(ctx->pgs->color[0].color_space->interpreter_data);
+
+ if (o == NULL || o->type != PDF_NAME)
+ return 0;
+
+ if (pdfi_name_cmp(n, (pdf_name *)o) == 0) {
+ if (n->object_num == o->object_num && n->indirect_num == o->indirect_num)
+ return 1;
+ }
+ return 0;
+}
+
int pdfi_setgraystroke(pdf_context *ctx);
int pdfi_setgrayfill(pdf_context *ctx);
int pdfi_setrgbstroke(pdf_context *ctx);
@@ -50,11 +86,14 @@ int pdfi_gs_setcolorspace(pdf_context *ctx, gs_color_space *pcs);
int pdfi_setcolorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_dict, pdf_dict *page_dict);
int pdfi_create_colorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_dict, pdf_dict *page_dict, gs_color_space **ppcs, bool inline_image);
int pdfi_create_icc_colorspace_from_stream(pdf_context *ctx, pdf_c_stream *stream, gs_offset_t offset,
- unsigned int length, int comps, int *icc_N, gs_color_space **ppcs);
+ unsigned int length, int comps, int *icc_N, ulong dictkey, gs_color_space **ppcs);
/* Page level spot colour detection and enumeration */
int pdfi_check_ColorSpace_for_spots(pdf_context *ctx, pdf_obj *space, pdf_dict *parent_dict, pdf_dict *page_dict, pdf_dict *spot_dict);
int pdfi_color_setoutputintent(pdf_context *ctx, pdf_dict *intent_dict, pdf_stream *profile);
+/* Sets up the DefaultRGB, DefaultCMYK and DefaultGray colour spaces if present */
+int pdfi_setup_DefaultSpaces(pdf_context *ctx, pdf_dict *source_dict);
+
#endif
diff --git a/pdf/pdf_deref.c b/pdf/pdf_deref.c
index fb3ce67b..91d77f63 100644
--- a/pdf/pdf_deref.c
+++ b/pdf/pdf_deref.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -240,12 +240,33 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
pdfi_pop(ctx, 1);
dict = NULL;
pdfi_push(ctx, (pdf_obj *)stream_obj);
- pdfi_countdown(stream_obj); /* get rid of extra ref */
stream_obj->stream_dict->indirect_num = stream_obj->stream_dict->object_num = objnum;
stream_obj->stream_dict->indirect_gen = stream_obj->stream_dict->generation_num = gen;
stream_obj->stream_offset = offset;
+ /* Exceptional code. Normally we do not need to worry about detecting circular references
+ * when reading objects, because we do not dereference any indirect objects. However streams
+ * are a slight exception in that we do get the Length from the stream dictionay and if that
+ * is an indirect reference, then we dereference it.
+ * OSS-fuzz bug 43247 has a stream where the value associated iwht the /Length is an indirect
+ * reference to the same stream object, and leads to infinite recursion. So deal with that
+ * possibility here.
+ */
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ return code;
+ }
+ if (pdfi_loop_detector_check_object(ctx, stream_obj->object_num))
+ return_error(gs_error_circular_reference);
+
+ code = pdfi_loop_detector_add_object(ctx, stream_obj->object_num);
+ if (code < 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ return code;
+ }
+
/* This code may be a performance overhead, it simply skips over the stream contents
* and checks that the stream ends with a 'endstream endobj' pair. We could add a
* 'go faster' flag for users who are certain their PDF files are well-formed. This
@@ -256,20 +277,28 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
if (code < 0) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Stream object %u missing mandatory keyword /Length, unable to verify the stream length.\n", objnum);
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ gs_snprintf(extra_info, sizeof(extra_info), "Stream object %u missing mandatory keyword /Length, unable to verify the stream length.\n", objnum);
pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAM, "pdfi_read_stream_object", extra_info);
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
return 0;
}
+ code = pdfi_loop_detector_cleartomark(ctx);
+ if (code < 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ return code;
+ }
if (i < 0 || (i + offset)> ctx->main_stream_length) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Stream object %u has /Length which, when added to offset of object, exceeds file size.\n", objnum);
+ gs_snprintf(extra_info, sizeof(extra_info), "Stream object %u has /Length which, when added to offset of object, exceeds file size.\n", objnum);
pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAM, "pdfi_read_stream_object", extra_info);
} else {
code = pdfi_seek(ctx, ctx->main_stream, i, SEEK_CUR);
if (code < 0) {
pdfi_pop(ctx, 1);
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
return code;
}
@@ -280,21 +309,28 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
if (code < 0 || pdfi_count_stack(ctx) < 2) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Failed to find a valid object at end of stream object %u.\n", objnum);
+ gs_snprintf(extra_info, sizeof(extra_info), "Failed to find a valid object at end of stream object %u.\n", objnum);
pdfi_log_info(ctx, "pdfi_read_stream_object", extra_info);
+ /* It is possible for pdfi_read_token to clear the stack, losing the stream object. If that
+ * happens give up.
+ */
+ if (pdfi_count_stack(ctx) == 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ return code;
+ }
}
else {
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Failed to find 'endstream' keyword at end of stream object %u.\n", objnum);
+ gs_snprintf(extra_info, sizeof(extra_info), "Failed to find 'endstream' keyword at end of stream object %u.\n", objnum);
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGENDOBJ, "pdfi_read_stream_object", extra_info);
} else {
keyword = ((pdf_keyword *)ctx->stack_top[-1]);
if (keyword->key != TOKEN_ENDSTREAM) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Stream object %u has an incorrect /Length of %"PRIu64"\n", objnum, i);
+ gs_snprintf(extra_info, sizeof(extra_info), "Stream object %u has an incorrect /Length of %"PRIu64"\n", objnum, i);
pdfi_log_info(ctx, "pdfi_read_stream_object", extra_info);
} else {
/* Cache the Length in the stream object and mark it valid */
@@ -316,17 +352,21 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
*/
if (stream_obj->length_valid != true) {
char Buffer[10];
- unsigned int loop, bytes, total = 0;
+ unsigned int bytes, total = 0;
+ int c = 0;
code = pdfi_seek(ctx, ctx->main_stream, stream_obj->stream_offset, SEEK_SET);
if (code < 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
pdfi_pop(ctx, 1);
return code;
}
memset(Buffer, 0x00, 10);
bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 9, ctx->main_stream);
- if (bytes < 9)
+ if (bytes < 9) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
return_error(gs_error_ioerror);
+ }
total = bytes;
do {
@@ -340,19 +380,22 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
stream_obj->length_valid = true;
break;
}
- for (loop = 0;loop < 9;loop++){
- Buffer[loop] = Buffer[loop + 1];
- }
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[9], 1, 1, ctx->main_stream);
- total += bytes;
- } while(bytes);
- if (bytes <= 0)
+ memmove(Buffer, Buffer+1, 9);
+ c = pdfi_read_byte(ctx, ctx->main_stream);
+ if (c < 0)
+ break;
+ Buffer[9] = (byte)c;
+ total++;
+ } while(1);
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ if (c < 0)
return_error(gs_error_ioerror);
return 0;
}
code = pdfi_read_token(ctx, ctx->main_stream, objnum, gen);
if (code < 0) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
if (ctx->args.pdfstoponerror)
return code;
else
@@ -363,10 +406,13 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
return 0;
}
- if (pdfi_count_stack(ctx) < 2)
+ if (pdfi_count_stack(ctx) < 2) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
return_error(gs_error_stackunderflow);
+ }
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
pdfi_pop(ctx, 1);
if (ctx->args.pdfstoponerror)
return_error(gs_error_typecheck);
@@ -376,6 +422,8 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
*/
return 0;
}
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+
keyword = ((pdf_keyword *)ctx->stack_top[-1]);
if (keyword->key != TOKEN_ENDOBJ) {
pdfi_pop(ctx, 2);
@@ -402,11 +450,15 @@ int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_
if (code < 0)
return code;
+ if (code == 0)
+ /* failed to read a token */
+ return_error(gs_error_syntaxerror);
+
do {
/* move all the saved offsets up by one */
saved_offset[0] = saved_offset[1];
saved_offset[1] = saved_offset[2];
- saved_offset[2] = pdfi_unread_tell(ctx);;
+ saved_offset[2] = pdfi_unread_tell(ctx);
code = pdfi_read_token(ctx, s, objnum, gen);
if (code < 0) {
@@ -415,6 +467,7 @@ int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_
}
if (s->eof)
return_error(gs_error_syntaxerror);
+ code = 0;
}while (ctx->stack_top[-1]->type != PDF_KEYWORD);
keyword = ((pdf_keyword *)ctx->stack_top[-1]);
@@ -494,6 +547,9 @@ static int pdfi_read_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t strea
code = pdfi_read_token(ctx, s, 0, 0);
if (code < 0)
return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
+
if (stack_size >= pdfi_count_stack(ctx))
return gs_note_error(gs_error_ioerror);
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_INT) {
@@ -506,6 +562,9 @@ static int pdfi_read_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t strea
code = pdfi_read_token(ctx, s, 0, 0);
if (code < 0)
return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
+
if (stack_size >= pdfi_count_stack(ctx))
return gs_note_error(gs_error_ioerror);
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_INT) {
@@ -535,14 +594,13 @@ static int pdfi_read_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t strea
}
static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object,
- const xref_entry *entry)
+ const xref_entry *entry, bool cache)
{
int code = 0;
- xref_entry *compressed_entry = &ctx->xref_table->xref[entry->u.compressed.compressed_stream_num];
+ xref_entry *compressed_entry;
pdf_c_stream *compressed_stream = NULL;
pdf_c_stream *SubFile_stream = NULL;
pdf_c_stream *Object_stream = NULL;
- char Buffer[256];
int i = 0, object_length = 0;
int64_t num_entries, found_object;
int64_t Length;
@@ -552,6 +610,11 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
pdf_name *Type = NULL;
pdf_obj *temp_obj;
+ if (entry->u.compressed.compressed_stream_num > ctx->xref_table->xref_size - 1)
+ return_error(gs_error_undefined);
+
+ compressed_entry = &ctx->xref_table->xref[entry->u.compressed.compressed_stream_num];
+
if (ctx->args.pdfdebug) {
dmprintf1(ctx->memory, "%% Reading compressed object (%"PRIi64" 0 obj)", obj);
dmprintf1(ctx->memory, " from ObjStm with object number %"PRIi64"\n", compressed_entry->object_num);
@@ -569,6 +632,11 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
if (code < 0)
goto exit;
+ if (pdfi_count_stack(ctx) < 1) {
+ code = gs_note_error(gs_error_stackunderflow);
+ goto exit;
+ }
+
if ((ctx->stack_top[-1])->type != PDF_STREAM) {
pdfi_pop(ctx, 1);
code = gs_note_error(gs_error_typecheck);
@@ -639,6 +707,10 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
code = pdfi_read_token(ctx, compressed_stream, obj, gen);
if (code < 0)
goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
temp_obj = ctx->stack_top[-1];
if (temp_obj->type != PDF_INT) {
code = gs_note_error(gs_error_typecheck);
@@ -650,9 +722,14 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
code = pdfi_read_token(ctx, compressed_stream, obj, gen);
if (code < 0)
goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
temp_obj = ctx->stack_top[-1];
if (temp_obj->type != PDF_INT) {
pdfi_pop(ctx, 1);
+ code = gs_note_error(gs_error_typecheck);
goto exit;
}
if (i == entry->u.compressed.object_index) {
@@ -671,8 +748,8 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
/* Skip to the offset of the object we want to read */
for (i=0;i < offset;i++)
{
- code = pdfi_read_bytes(ctx, (byte *)&Buffer[0], 1, 1, compressed_stream);
- if (code <= 0) {
+ int c = pdfi_read_byte(ctx, compressed_stream);
+ if (c < 0) {
code = gs_note_error(gs_error_ioerror);
goto exit;
}
@@ -696,6 +773,10 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
code = pdfi_read_token(ctx, Object_stream, obj, gen);
if (code < 0)
goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
if (ctx->stack_top[-1]->type == PDF_ARRAY_MARK || ctx->stack_top[-1]->type == PDF_DICT_MARK) {
int start_depth = pdfi_count_stack(ctx);
@@ -704,6 +785,10 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
code = pdfi_read_token(ctx, Object_stream, obj, gen);
if (code < 0)
goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
if (compressed_stream->eof == true) {
code = gs_note_error(gs_error_ioerror);
goto exit;
@@ -720,10 +805,12 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
pdfi_countup(*object);
pdfi_pop(ctx, 1);
- code = pdfi_add_to_cache(ctx, *object);
- if (code < 0) {
- pdfi_countdown(*object);
- goto exit;
+ if (cache) {
+ code = pdfi_add_to_cache(ctx, *object);
+ if (code < 0) {
+ pdfi_countdown(*object);
+ goto exit;
+ }
}
exit:
@@ -742,7 +829,7 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
/* pdf_dereference returns an object with a reference count of at least 1, this represents the
* reference being held by the caller (in **object) when we return from this function.
*/
-int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object)
+static int pdfi_dereference_main(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object, bool cache)
{
xref_entry *entry;
int code, stack_depth = pdfi_count_stack(ctx);
@@ -757,7 +844,7 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
if (obj >= ctx->xref_table->xref_size) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Error, attempted to dereference object %"PRIu64", which is not present in the xref table\n", obj);
+ gs_snprintf(extra_info, sizeof(extra_info), "Error, attempted to dereference object %"PRIu64", which is not present in the xref table\n", obj);
pdfi_set_error(ctx, 0, NULL, E_PDF_BADOBJNUMBER, "pdfi_dereference", extra_info);
if(ctx->args.pdfstoponerror)
@@ -777,13 +864,18 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
if (entry->free) {
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Attempt to dereference free object %"PRIu64", trying next object number as offset.\n", entry->object_num);
+ gs_snprintf(extra_info, sizeof(extra_info), "Attempt to dereference free object %"PRIu64", trying next object number as offset.\n", entry->object_num);
pdfi_set_error(ctx, 0, NULL, E_PDF_DEREF_FREE_OBJ, "pdfi_dereference", extra_info);
}
if (ctx->loop_detection) {
if (pdfi_loop_detector_check_object(ctx, obj) == true)
return_error(gs_error_circular_reference);
+ if (entry->free) {
+ code = pdfi_loop_detector_add_object(ctx, obj);
+ if (code < 0)
+ return code;
+ }
}
if (entry->cache != NULL){
pdf_obj_cache_entry *cache_entry = entry->cache;
@@ -802,12 +894,11 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
/* This is an object in a compressed object stream */
ctx->encryption.decrypt_strings = false;
- code = pdfi_deref_compressed(ctx, obj, gen, object, entry);
+ code = pdfi_deref_compressed(ctx, obj, gen, object, entry, cache);
if (code < 0 || *object == NULL)
goto error;
} else {
pdf_c_stream *SubFile_stream = NULL;
- pdf_string *EODString;
#if CACHE_STATISTICS
ctx->misses++;
#endif
@@ -817,20 +908,17 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
if (code < 0)
goto error;
- code = pdfi_name_alloc(ctx, (byte *)"trailer", 6, (pdf_obj **)&EODString);
+ code = pdfi_apply_SubFileDecode_filter(ctx, 0, "trailer", ctx->main_stream, &SubFile_stream, false);
if (code < 0)
goto error;
- pdfi_countup(EODString);
-
- code = pdfi_apply_SubFileDecode_filter(ctx, 0, EODString, ctx->main_stream, &SubFile_stream, false);
- if (code < 0) {
- pdfi_countdown(EODString);
- goto error;
- }
code = pdfi_read_object(ctx, SubFile_stream, entry->u.uncompressed.offset);
- pdfi_countdown(EODString);
+ /* pdfi_read_object() could do a repair, which would invalidate the xref and rebuild it.
+ * reload the xref entry to be certain it is valid.
+ */
+ entry = &ctx->xref_table->xref[obj];
+
pdfi_close_file(ctx, SubFile_stream);
if (code < 0) {
int code1 = 0;
@@ -848,7 +936,7 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
code1 = pdfi_repair_file(ctx);
if (code1 == 0)
- return pdfi_dereference(ctx, obj, gen, object);
+ return pdfi_dereference_main(ctx, obj, gen, object, cache);
/* Repair failed, just give up and return an error */
return code;
}
@@ -857,10 +945,12 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
*object = ctx->stack_top[-1];
pdfi_countup(*object);
pdfi_pop(ctx, 1);
- code = pdfi_add_to_cache(ctx, *object);
- if (code < 0) {
- pdfi_countdown(*object);
- goto error;
+ if (cache) {
+ code = pdfi_add_to_cache(ctx, *object);
+ if (code < 0) {
+ pdfi_countdown(*object);
+ goto error;
+ }
}
} else {
pdfi_pop(ctx, 1);
@@ -897,6 +987,16 @@ error:
return code;
}
+int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object)
+{
+ return pdfi_dereference_main(ctx, obj, gen, object, true);
+}
+
+int pdfi_dereference_nocache(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object)
+{
+ return pdfi_dereference_main(ctx, obj, gen, object, false);
+}
+
/* do a derefence with loop detection */
int pdfi_deref_loop_detect(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object)
{
@@ -911,6 +1011,18 @@ int pdfi_deref_loop_detect(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj
return code;
}
+int pdfi_deref_loop_detect_nocache(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object)
+{
+ int code;
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ code = pdfi_dereference_nocache(ctx, obj, gen, object);
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ return code;
+}
static int pdfi_resolve_indirect_array(pdf_context *ctx, pdf_obj *obj, bool recurse)
{
@@ -921,7 +1033,20 @@ static int pdfi_resolve_indirect_array(pdf_context *ctx, pdf_obj *obj, bool recu
arraysize = pdfi_array_size(array);
for (index = 0; index < arraysize; index++) {
+ if (ctx->loop_detection != NULL) {
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+ }
+
code = pdfi_array_get_no_store_R(ctx, array, index, &object);
+
+ if (ctx->loop_detection != NULL) {
+ int code1 = pdfi_loop_detector_cleartomark(ctx);
+ if (code1 < 0)
+ return code1;
+ }
+
if (code == gs_error_circular_reference) {
/* Just leave as an indirect ref */
code = 0;
@@ -931,7 +1056,7 @@ static int pdfi_resolve_indirect_array(pdf_context *ctx, pdf_obj *obj, bool recu
if (object->type != PDF_STREAM)
code = pdfi_array_put(ctx, array, index, object);
if (recurse)
- code = pdfi_resolve_indirect(ctx, object, recurse);
+ code = pdfi_resolve_indirect_loop_detect(ctx, NULL, object, recurse);
}
if (code < 0) goto exit;
@@ -958,8 +1083,24 @@ static int pdfi_resolve_indirect_dict(pdf_context *ctx, pdf_obj *obj, bool recur
* circular references.
*/
for (index=0; index<dictsize; index ++) {
- Key = (pdf_name *)dict->keys[index];
+ Key = (pdf_name *)dict->list[index].key;
+ if (pdfi_name_is(Key, "Parent"))
+ continue;
+
+ if (ctx->loop_detection != NULL) {
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+ }
+
code = pdfi_dict_get_no_store_R_key(ctx, dict, Key, &Value);
+
+ if (ctx->loop_detection != NULL) {
+ int code1 = pdfi_loop_detector_cleartomark(ctx);
+ if (code1 < 0)
+ return code1;
+ }
+
if (code == gs_error_circular_reference) {
/* Just leave as an indirect ref */
code = 0;
@@ -967,9 +1108,9 @@ static int pdfi_resolve_indirect_dict(pdf_context *ctx, pdf_obj *obj, bool recur
if (code < 0) goto exit;
/* don't store the object if it's a stream (leave as a ref) */
if (Value->type != PDF_STREAM)
- pdfi_dict_put_obj(ctx, dict, (pdf_obj *)Key, Value);
+ pdfi_dict_put_obj(ctx, dict, (pdf_obj *)Key, Value, true);
if (recurse)
- code = pdfi_resolve_indirect(ctx, Value, recurse);
+ code = pdfi_resolve_indirect_loop_detect(ctx, NULL, Value, recurse);
}
if (code < 0) goto exit;
@@ -1016,11 +1157,16 @@ int pdfi_resolve_indirect_loop_detect(pdf_context *ctx, pdf_obj *parent, pdf_obj
code = pdfi_loop_detector_add_object(ctx, parent->object_num);
if (code < 0) goto exit;
}
+
if (value->object_num != 0) {
+ if (pdfi_loop_detector_check_object(ctx, value->object_num)) {
+ code = gs_note_error(gs_error_circular_reference);
+ goto exit;
+ }
code = pdfi_loop_detector_add_object(ctx, value->object_num);
if (code < 0) goto exit;
}
- code = pdfi_resolve_indirect(ctx, value, false);
+ code = pdfi_resolve_indirect(ctx, value, recurse);
exit:
(void)pdfi_loop_detector_cleartomark(ctx); /* Clear to the mark for the current loop */
diff --git a/pdf/pdf_deref.h b/pdf/pdf_deref.h
index 132be7dd..71d89168 100644
--- a/pdf/pdf_deref.h
+++ b/pdf/pdf_deref.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -19,7 +19,9 @@
int replace_cache_entry(pdf_context *ctx, pdf_obj *o);
int is_compressed_object(pdf_context *ctx, uint32_t obj, uint32_t gen);
int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object);
+int pdfi_dereference_nocache(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object);
int pdfi_deref_loop_detect(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object);
+int pdfi_deref_loop_detect_nocache(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **object);
int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_offset, uint32_t objnum, uint32_t gen);
int pdfi_resolve_indirect(pdf_context *ctx, pdf_obj *value, bool recurse);
int pdfi_resolve_indirect_loop_detect(pdf_context *ctx, pdf_obj *parent, pdf_obj *value, bool recurse);
diff --git a/pdf/pdf_device.c b/pdf/pdf_device.c
index 6d7547e2..9ed97133 100644
--- a/pdf/pdf_device.c
+++ b/pdf/pdf_device.c
@@ -18,8 +18,10 @@
#include "pdf_int.h"
#include "pdf_stack.h"
#include "pdf_device.h"
-#include "gdevvec.h" /* for gs_device_vector */
-#include "gxdevsop.h" /* For special ops : dev_param_req_t */
+#include "gsdevice.h" /* For gs_setdevice_no_erase */
+#include "gspaint.h" /* For gs_erasepage */
+#include "gdevvec.h" /* for gs_device_vector */
+#include "gxdevsop.h" /* For special ops : dev_param_req_t */
int pdfi_device_check_param(gx_device *dev, const char *param, gs_c_param_list *list)
{
diff --git a/pdf/pdf_dict.c b/pdf/pdf_dict.c
index 4b65404e..34356dfe 100644
--- a/pdf/pdf_dict.c
+++ b/pdf/pdf_dict.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -24,6 +24,9 @@
#include "pdf_loop_detect.h"
#include "pdf_misc.h"
+static int pdfi_dict_find(pdf_context *ctx, pdf_dict *d, const char *Key, bool sort);
+static int pdfi_dict_find_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, bool sort);
+
void pdfi_free_dict(pdf_obj *o)
{
pdf_dict *d = (pdf_dict *)o;
@@ -34,15 +37,14 @@ void pdfi_free_dict(pdf_obj *o)
for (i=0;i < d->entries;i++) {
#if DEBUG_DICT
- name = (pdf_name *)d->keys[i];
+ name = (pdf_name *)d->list[i].key;
#endif
- if (d->values[i] != NULL)
- pdfi_countdown(d->values[i]);
- if (d->keys[i] != NULL)
- pdfi_countdown(d->keys[i]);
+ if (d->list[i].value != NULL)
+ pdfi_countdown(d->list[i].value);
+ if (d->list[i].key != NULL)
+ pdfi_countdown(d->list[i].key);
}
- gs_free_object(OBJ_MEMORY(d), d->keys, "pdf interpreter free dictionary keys");
- gs_free_object(OBJ_MEMORY(d), d->values, "pdf interpreter free dictioanry values");
+ gs_free_object(OBJ_MEMORY(d), d->list, "pdf interpreter free dictionary key/values");
gs_free_object(OBJ_MEMORY(d), d, "pdf interpreter free dictionary");
}
@@ -55,31 +57,22 @@ static int pdfi_dict_delete_inner(pdf_context *ctx, pdf_dict *d, pdf_name *n, co
pdf_name *name;
#endif
- for (i=0;i < d->entries;i++) {
-#if DEBUG_DICT
- name = (pdf_name *)d->keys[i];
-#endif
- if (n != NULL) {
- if (pdfi_name_cmp(n, (pdf_name *)d->keys[i]) == 0)
- break;
- } else {
- if (pdfi_name_is((pdf_name *)d->keys[i], str))
- break;
- }
+ if (n != NULL)
+ i = pdfi_dict_find_key(ctx, d, (const pdf_name *)n, false);
+ else
+ i = pdfi_dict_find(ctx, d, str, false);
- }
- if (i >= d->entries)
- return_error(gs_error_undefined);
-
- pdfi_countdown(d->keys[i]);
- pdfi_countdown(d->values[i]);
- for( ;i < d->entries - 1;i++) {
- d->keys[i] = d->keys[i + 1];
- d->values[i] = d->values[i + 1];
- }
- d->keys[i] = NULL;
- d->values[i] = NULL;
+ if (i < 0)
+ return i;
+
+ pdfi_countdown(d->list[i].key);
+ pdfi_countdown(d->list[i].value);
d->entries--;
+ if (i != d->entries)
+ memmove(&d->list[i], &d->list[i+1], (d->entries - i) * sizeof(d->list[0]));
+ d->list[d->entries].key = NULL;
+ d->list[d->entries].value = NULL;
+ d->is_sorted = false;
return 0;
}
@@ -104,7 +97,17 @@ int pdfi_dict_alloc(pdf_context *ctx, uint64_t size, pdf_dict **d)
return pdfi_object_alloc(ctx, PDF_DICT, size, (pdf_obj **)d);
}
-int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen)
+static int pdfi_dict_name_from_string(pdf_context *ctx, pdf_string *s, pdf_name **n)
+{
+ int code = pdfi_object_alloc(ctx, PDF_NAME, s->length, (pdf_obj **)n);
+ if (code >= 0) {
+ memcpy((*n)->data, s->data, s->length);
+ pdfi_countup(*n);
+ }
+ return code;
+}
+
+int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen, bool convert_string_keys)
{
uint64_t index = 0;
pdf_dict *d = NULL;
@@ -138,17 +141,31 @@ int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indir
/* In PDF keys are *required* to be names, so we ought to check that here */
if (((pdf_obj *)ctx->stack_top[-2])->type == PDF_NAME) {
- d->keys[i] = ctx->stack_top[-2];
- pdfi_countup(d->keys[i]);
+ d->list[i].key = ctx->stack_top[-2];
+ pdfi_countup(d->list[i].key);
#if DEBUG_DICT
- key = (pdf_name *)d->keys[i];
+ key = (pdf_name *)d->list[i].key;
#endif
- d->values[i] = ctx->stack_top[-1];
- pdfi_countup(d->values[i]);
+ d->list[i].value = ctx->stack_top[-1];
+ pdfi_countup(d->list[i].value);
} else {
- pdfi_free_dict((pdf_obj *)d);
- pdfi_clear_to_mark(ctx);
- return_error(gs_error_typecheck);
+ if (convert_string_keys && ((pdf_obj *)ctx->stack_top[-2])->type == PDF_STRING) {
+ pdf_name *n;
+ code = pdfi_dict_name_from_string(ctx, (pdf_string *)ctx->stack_top[-2], &n);
+ if (code < 0) {
+ pdfi_free_dict((pdf_obj *)d);
+ pdfi_clear_to_mark(ctx);
+ return_error(gs_error_typecheck);
+ }
+ d->list[i].key = (pdf_obj *)n; /* pdfi_dict_name_from_string() sets refcnt to 1 */
+ d->list[i].value = ctx->stack_top[-1];
+ pdfi_countup(d->list[i].value);
+ }
+ else {
+ pdfi_free_dict((pdf_obj *)d);
+ pdfi_clear_to_mark(ctx);
+ return_error(gs_error_typecheck);
+ }
}
pdfi_pop(ctx, 2);
@@ -187,40 +204,155 @@ pdfi_dict_get2(pdf_context *ctx, pdf_dict *d, const char *Key1,
return code;
}
+static int pdfi_dict_compare_entry(const void *a, const void *b)
+{
+ pdf_name *key_a = (pdf_name *)((pdf_dict_entry *)a)->key, *key_b = (pdf_name *)((pdf_dict_entry *)b)->key;
+
+ if (key_a == NULL) {
+ if (key_b == NULL)
+ return 0;
+ else
+ return 1;
+ }
+
+ if (key_b == NULL)
+ return -1;
+
+ if (key_a->length != key_b->length)
+ return key_a->length - key_b->length;
+
+ return strncmp((const char *)key_a->data, (const char *)key_b->data, key_a->length);
+}
+
+static int pdfi_dict_find_sorted(pdf_context *ctx, pdf_dict *d, const char *Key)
+{
+ int start = 0, end = d->size - 1, middle = 0, keylen = strlen(Key);
+ pdf_name *test_key;
+
+ while (start <= end) {
+ middle = start + (end - start) / 2;
+ test_key = (pdf_name *)d->list[middle].key;
+
+ /* Sorting pushes unused key/values (NULL) to the end of the dictionary */
+ if (test_key == NULL) {
+ end = middle - 1;
+ continue;
+ }
+
+ if (test_key->length == keylen) {
+ int result = strncmp((const char *)test_key->data, Key, keylen);
+
+ if (result == 0)
+ return middle;
+ if (result < 0)
+ start = middle + 1;
+ else
+ end = middle - 1;
+ } else {
+ if (test_key->length < keylen)
+ start = middle + 1;
+ else
+ end = middle -1;
+ }
+ }
+ return gs_note_error(gs_error_undefined);
+}
+
+static int pdfi_dict_find_unsorted(pdf_context *ctx, pdf_dict *d, const char *Key)
+{
+ int i;
+ pdf_name *t;
+
+ for (i=0;i< d->entries;i++) {
+ t = (pdf_name *)d->list[i].key;
+
+ if (t && t->type == PDF_NAME) {
+ if (pdfi_name_is((pdf_name *)t, Key)) {
+ return i;
+ }
+ }
+ }
+ return_error(gs_error_undefined);
+}
+
+static int pdfi_dict_find(pdf_context *ctx, pdf_dict *d, const char *Key, bool sort)
+{
+ if (!d->is_sorted) {
+ if (d->entries > 32 && sort) {
+ qsort(d->list, d->size, sizeof(pdf_dict_entry), pdfi_dict_compare_entry);
+ d->is_sorted = true;
+ return pdfi_dict_find_sorted(ctx, d, Key);
+ } else
+ return pdfi_dict_find_unsorted(ctx, d, Key);
+ } else
+ return pdfi_dict_find_sorted(ctx, d, Key);
+}
+
+static int pdfi_dict_find_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, bool sort)
+{
+ char *Test = NULL;
+ int index = 0;
+
+ Test = (char *)gs_alloc_bytes(ctx->memory, Key->length + 1, "pdfi_dict_find_key");
+ if (Test == NULL)
+ return_error(gs_error_VMerror);
+
+ memcpy(Test, Key->data, Key->length);
+ Test[Key->length] = 0x00;
+
+ index = pdfi_dict_find(ctx, d, Test, sort);
+
+ gs_free_object(ctx->memory, Test, "pdfi_dict_find_key");
+ return index;
+}
+
/* The object returned by pdfi_dict_get has its reference count incremented by 1 to
* indicate the reference now held by the caller, in **o.
*/
-int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o)
+int pdfi_dict_get_common(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o, bool cache)
{
- int i=0, code;
- pdf_name *t;
+ int index = 0, code = 0;
*o = NULL;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ index = pdfi_dict_find(ctx, d, Key, true);
+ if (index < 0)
+ return index;
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_is((pdf_name *)t, Key)) {
- if (d->values[i]->type == PDF_INDIRECT) {
- pdf_indirect_ref *r = (pdf_indirect_ref *)d->values[i];
-
- code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o);
- if (code < 0)
- return code;
- pdfi_countdown(d->values[i]);
- d->values[i] = *o;
- }
- *o = d->values[i];
- pdfi_countup(*o);
- return 0;
- }
+ if (d->list[index].value->type == PDF_INDIRECT) {
+ pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value;
+
+ if (r->ref_object_num == d->object_num)
+ return_error(gs_error_circular_reference);
+
+ if (cache)
+ code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o);
+ else
+ code = pdfi_deref_loop_detect_nocache(ctx, r->ref_object_num, r->ref_generation_num, o);
+ if (code < 0)
+ return code;
+ /* The file Bug690138.pdf has font dictionaries which contain ToUnicode keys where
+ * the value is an indirect reference to the same font object. If we replace the
+ * indirect reference in the dictionary with the font dictionary it becomes self
+ * referencing and never counts down to 0, leading to a memory leak.
+ * This is clearly an error, so flag it and don't replace the indirect reference.
+ */
+ if ((*o)->object_num == 0 || (*o)->object_num != d->object_num)
+ {
+ pdfi_countdown(d->list[index].value);
+ d->list[index].value = *o;
+ } else {
+ pdfi_set_error(ctx, 0, NULL, E_DICT_SELF_REFERENCE, "pdfi_dict_get", NULL);
+ return 0;
}
}
- return_error(gs_error_undefined);
+ *o = d->list[index].value;
+ pdfi_countup(*o);
+
+ return code;
}
/* Get object from dict without resolving indirect references
@@ -228,26 +360,20 @@ int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o)
*/
int pdfi_dict_get_no_deref(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o)
{
- int i=0;
- pdf_name *t;
+ int index=0;
*o = NULL;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ index = pdfi_dict_find_key(ctx, d, Key, true);
+ if (index < 0)
+ return index;
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_cmp((pdf_name *)t, Key)== 0) {
- *o = d->values[i];
- pdfi_countup(*o);
- return 0;
- }
- }
- }
- return_error(gs_error_undefined);
+ *o = d->list[index].value;
+ pdfi_countup(*o);
+ return 0;
}
/* Get by pdf_name rather than by char *
@@ -256,64 +382,52 @@ int pdfi_dict_get_no_deref(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, p
*/
int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o)
{
- int i=0, code;
- pdf_name *t;
+ int index=0, code = 0;
*o = NULL;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ index = pdfi_dict_find_key(ctx, d, Key, true);
+ if (index < 0)
+ return index;
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_cmp((pdf_name *)t, Key)== 0) {
- if (d->values[i]->type == PDF_INDIRECT) {
- pdf_indirect_ref *r = (pdf_indirect_ref *)d->values[i];
-
- code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o);
- if (code < 0)
- return code;
- pdfi_countdown(d->values[i]);
- d->values[i] = *o;
- }
- *o = d->values[i];
- pdfi_countup(*o);
- return 0;
- }
- }
+ if (d->list[index].value->type == PDF_INDIRECT) {
+ pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value;
+
+ code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o);
+ if (code < 0)
+ return code;
+ pdfi_countdown(d->list[index].value);
+ d->list[index].value = *o;
}
- return_error(gs_error_undefined);
+ *o = d->list[index].value;
+ pdfi_countup(*o);
+ return 0;
}
/* Get indirect reference without de-referencing it */
int pdfi_dict_get_ref(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_indirect_ref **o)
{
- int i=0;
- pdf_name *t;
+ int index=0;
*o = NULL;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ index = pdfi_dict_find(ctx, d, Key, true);
+ if (index < 0)
+ return index;
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_is((pdf_name *)t, Key)) {
- if (d->values[i]->type == PDF_INDIRECT) {
- *o = (pdf_indirect_ref *)d->values[i];
- pdfi_countup(*o);
- return 0;
- } else {
- return_error(gs_error_typecheck);
- }
- }
- }
+ if (d->list[index].value->type == PDF_INDIRECT) {
+ *o = (pdf_indirect_ref *)d->list[index].value;
+ pdfi_countup(*o);
+ return 0;
+ } else {
+ return_error(gs_error_typecheck);
}
- return_error(gs_error_undefined);
}
/* As per pdfi_dict_get(), but doesn't replace an indirect reference in a dictionary with a
@@ -326,42 +440,32 @@ int pdfi_dict_get_ref(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_indire
static int pdfi_dict_get_no_store_R_inner(pdf_context *ctx, pdf_dict *d, const char *strKey,
const pdf_name *nameKey, pdf_obj **o)
{
- int i=0, code;
- pdf_name *t;
- bool match = false;
+ int index=0, code = 0;
*o = NULL;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ if (strKey == NULL)
+ index = pdfi_dict_find_key(ctx, d, nameKey, true);
+ else
+ index = pdfi_dict_find(ctx, d, strKey, true);
- if (t && t->type == PDF_NAME) {
- if (strKey != NULL) {
- if (pdfi_name_is(t, strKey))
- match = true;
- } else {
- if (!pdfi_name_cmp(t, nameKey))
- match = true;
- }
- if (match) {
- if (d->values[i]->type == PDF_INDIRECT) {
- pdf_indirect_ref *r = (pdf_indirect_ref *)d->values[i];
-
- code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, o);
- if (code < 0)
- return code;
- } else {
- *o = d->values[i];
- pdfi_countup(*o);
- }
- return 0;
- }
- }
+ if (index < 0)
+ return index;
+
+ if (d->list[index].value->type == PDF_INDIRECT) {
+ pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value;
+
+ code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, o);
+ if (code < 0)
+ return code;
+ } else {
+ *o = d->list[index].value;
+ pdfi_countup(*o);
}
- return_error(gs_error_undefined);
+ return 0;
}
/* Wrapper to pdfi_dict_no_store_R_inner(), takes a char * as Key */
@@ -715,12 +819,14 @@ int pdfi_make_int_array_from_dict(pdf_context *ctx, int **parray, pdf_dict *dict
return array_size;
}
-/* Put into dictionary with key as object */
-int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *value)
+/* Put into dictionary with key as object -
+ If the key already exists, we'll only replace it
+ if "replace" is true.
+*/
+int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *value, bool replace)
{
- uint64_t i;
- pdf_obj **new_keys, **new_values;
- pdf_name *n;
+ int i;
+ pdf_dict_entry *new_list;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
@@ -729,29 +835,27 @@ int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *valu
return_error(gs_error_typecheck);
/* First, do we have a Key/value pair already ? */
- for (i=0;i< d->entries;i++) {
- n = (pdf_name *)d->keys[i];
- if (n && n->type == PDF_NAME) {
- if (pdfi_name_cmp((pdf_name *)Key, n) == 0) {
- if (d->values[i] == value)
- /* We already have this value stored with this key.... */
- return 0;
- pdfi_countdown(d->values[i]);
- d->values[i] = value;
- pdfi_countup(value);
- return 0;
- }
- }
+ i = pdfi_dict_find_key(ctx, d, (pdf_name *)Key, false);
+ if (i >= 0) {
+ if (d->list[i].value == value || replace == false)
+ /* We already have this value stored with this key.... */
+ return 0;
+ pdfi_countdown(d->list[i].value);
+ d->list[i].value = value;
+ pdfi_countup(value);
+ return 0;
}
+ d->is_sorted = false;
+
/* Nope, its a new Key */
if (d->size > d->entries) {
/* We have a hole, find and use it */
for (i=0;i< d->size;i++) {
- if (d->keys[i] == NULL) {
- d->keys[i] = Key;
+ if (d->list[i].key == NULL) {
+ d->list[i].key = Key;
pdfi_countup(Key);
- d->values[i] = value;
+ d->list[i].value = value;
pdfi_countup(value);
d->entries++;
return 0;
@@ -759,24 +863,18 @@ int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *valu
}
}
- new_keys = (pdf_obj **)gs_alloc_bytes(ctx->memory, (d->size + 1) * sizeof(pdf_obj *), "pdfi_dict_put reallocate dictionary keys");
- new_values = (pdf_obj **)gs_alloc_bytes(ctx->memory, (d->size + 1) * sizeof(pdf_obj *), "pdfi_dict_put reallocate dictionary values");
- if (new_keys == NULL || new_values == NULL){
- gs_free_object(ctx->memory, new_keys, "pdfi_dict_put memory allocation failure");
- gs_free_object(ctx->memory, new_values, "pdfi_dict_put memory allocation failure");
+ new_list = (pdf_dict_entry *)gs_alloc_bytes(ctx->memory, (d->size + 1) * sizeof(pdf_dict_entry), "pdfi_dict_put reallocate dictionary key/values");
+ if (new_list == NULL) {
return_error(gs_error_VMerror);
}
- memcpy(new_keys, d->keys, d->size * sizeof(pdf_obj *));
- memcpy(new_values, d->values, d->size * sizeof(pdf_obj *));
+ memcpy(new_list, d->list, d->size * sizeof(pdf_dict_entry));
- gs_free_object(ctx->memory, d->keys, "pdfi_dict_put key reallocation");
- gs_free_object(ctx->memory, d->values, "pdfi_dict_put value reallocation");
+ gs_free_object(ctx->memory, d->list, "pdfi_dict_put key/value reallocation");
- d->keys = new_keys;
- d->values = new_values;
+ d->list = new_list;
- d->keys[d->size] = Key;
- d->values[d->size] = value;
+ d->list[d->size].key = Key;
+ d->list[d->size].value = value;
d->size++;
d->entries++;
pdfi_countup(Key);
@@ -796,7 +894,7 @@ int pdfi_dict_put(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value
return code;
pdfi_countup(key);
- code = pdfi_dict_put_obj(ctx, d, key, value);
+ code = pdfi_dict_put_obj(ctx, d, key, value, true);
pdfi_countdown(key); /* get rid of extra ref */
return code;
}
@@ -847,9 +945,10 @@ int pdfi_dict_copy(pdf_context *ctx, pdf_dict *target, pdf_dict *source)
int i=0, code = 0;
for (i=0;i< source->entries;i++) {
- code = pdfi_dict_put_obj(ctx, target, source->keys[i], source->values[i]);
+ code = pdfi_dict_put_obj(ctx, target, source->list[i].key, source->list[i].value, true);
if (code < 0)
return code;
+ target->is_sorted = source->is_sorted;
}
return 0;
}
@@ -857,26 +956,34 @@ int pdfi_dict_copy(pdf_context *ctx, pdf_dict *target, pdf_dict *source)
int pdfi_dict_known(pdf_context *ctx, pdf_dict *d, const char *Key, bool *known)
{
int i;
- pdf_name *t;
if (d->type != PDF_DICT)
return_error(gs_error_typecheck);
*known = false;
- for (i=0;i< d->entries;i++) {
- t = (pdf_name *)d->keys[i];
+ i = pdfi_dict_find(ctx, d, Key, true);
+ if (i >= 0)
+ *known = true;
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_is(t, Key)) {
- *known = true;
- break;
- }
- }
- }
return 0;
}
-/* Tests if a Key is present in the dictionary, if it is, retrieves the value associted with the
+int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *known)
+{
+ int i;
+
+ if (d->type != PDF_DICT)
+ return_error(gs_error_typecheck);
+
+ *known = false;
+ i = pdfi_dict_find_key(ctx, d, Key, true);
+ if (i >= 0)
+ *known = true;
+
+ return 0;
+}
+
+/* Tests if a Key is present in the dictionary, if it is, retrieves the value associated with the
* key. Returns < 0 for error, 0 if the key is not found > 0 if the key is present, and initialises
* the value in the arguments. Since this uses pdf_dict_get(), the returned value has its
* reference count incremented by 1, just like pdfi_dict_get().
@@ -944,28 +1051,6 @@ int pdfi_dict_knownget_number(pdf_context *ctx, pdf_dict *d, const char *Key, do
return 1;
}
-int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *known)
-{
- int i;
- pdf_obj *t;
-
- if (d->type != PDF_DICT)
- return_error(gs_error_typecheck);
-
- *known = false;
- for (i=0;i< d->entries;i++) {
- t = d->keys[i];
-
- if (t && t->type == PDF_NAME) {
- if (pdfi_name_cmp((pdf_name *)t, Key) == 0) {
- *known = true;
- break;
- }
- }
- }
- return 0;
-}
-
int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value, uint64_t *index)
{
int code;
@@ -987,14 +1072,14 @@ int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value
* dictionary somehow ends up with NULL keys in the allocated
* section.
*/
- *Key = d->keys[*index];
+ *Key = d->list[*index].key;
if (*Key == NULL) {
(*index)++;
continue;
}
- if (d->values[*index]->type == PDF_INDIRECT) {
- pdf_indirect_ref *r = (pdf_indirect_ref *)d->values[*index];
+ if (d->list[*index].value->type == PDF_INDIRECT) {
+ pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[*index].value;
pdf_obj *o;
code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, &o);
@@ -1005,7 +1090,7 @@ int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value
*Value = o;
break;
} else {
- *Value = d->values[*index];
+ *Value = d->list[*index].value;
pdfi_countup(*Value);
break;
}
@@ -1037,7 +1122,7 @@ int pdfi_dict_key_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, uint64_t *i
return gs_error_undefined;
}
- *Key = d->keys[*i];
+ *Key = d->list[*i].key;
if (*Key == NULL) {
(*i)++;
continue;
@@ -1063,15 +1148,16 @@ int pdfi_merge_dicts(pdf_context *ctx, pdf_dict *target, pdf_dict *source)
bool known = false;
for (i=0;i< source->entries;i++) {
- code = pdfi_dict_known_by_key(ctx, target, (pdf_name *)source->keys[i], &known);
+ code = pdfi_dict_known_by_key(ctx, target, (pdf_name *)source->list[i].key, &known);
if (code < 0)
return code;
if (!known) {
- code = pdfi_dict_put_obj(ctx, target, source->keys[i], source->values[i]);
+ code = pdfi_dict_put_obj(ctx, target, source->list[i].key, source->list[i].value, true);
if (code < 0)
return code;
}
}
+ target->is_sorted = false;
return 0;
}
diff --git a/pdf/pdf_dict.h b/pdf/pdf_dict.h
index 269f6be5..c5a8743b 100644
--- a/pdf/pdf_dict.h
+++ b/pdf/pdf_dict.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -20,24 +20,35 @@
static inline uint64_t pdfi_dict_entries(pdf_dict *d) { return d->entries; }
+int pdfi_dict_get_common(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o, bool cache);
+static inline int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o)
+{
+ return pdfi_dict_get_common(ctx, d, Key, o, true);
+}
+
+static inline int pdfi_dict_get_nocache(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o)
+{
+ return pdfi_dict_get_common(ctx, d, Key, o, true);
+}
+
+
void pdfi_free_dict(pdf_obj *o);
int pdfi_dict_delete_pair(pdf_context *ctx, pdf_dict *d, pdf_name *n);
int pdfi_dict_delete(pdf_context *ctx, pdf_dict *d, const char *str);
int pdfi_dict_alloc(pdf_context *ctx, uint64_t size, pdf_dict **d);
-int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen);
+int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen, bool convert_string_keys);
int pdfi_dict_known(pdf_context *ctx, pdf_dict *d, const char *Key, bool *known);
int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *known);
int pdfi_dict_knownget(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o);
int pdfi_dict_knownget_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type type, pdf_obj **o);
int pdfi_dict_knownget_number(pdf_context *ctx, pdf_dict *d, const char *Key, double *f);
int pdfi_merge_dicts(pdf_context *ctx, pdf_dict *target, pdf_dict *source);
-int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *value);
+int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *value, bool replace);
int pdfi_dict_put(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value);
int pdfi_dict_put_int(pdf_context *ctx, pdf_dict *d, const char *Key, int64_t value);
int pdfi_dict_put_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool value);
int pdfi_dict_put_name(pdf_context *ctx, pdf_dict *d, const char *Key, const char *name);
int pdfi_dict_get2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, pdf_obj **o);
-int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o);
int pdfi_dict_get_no_deref(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o);
int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o);
int pdfi_dict_get_no_store_R_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o);
diff --git a/pdf/pdf_doc.c b/pdf/pdf_doc.c
index 5f87d079..be71dfcb 100644
--- a/pdf/pdf_doc.c
+++ b/pdf/pdf_doc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -105,11 +105,16 @@ int pdfi_read_Info(pdf_context *ctx)
{
pdf_dict *Info;
int code;
+ pdf_dict *d;
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "%% Reading Info dictionary\n");
+ /* See comment in pdfi_read_Root() for details */
+ d = ctx->Trailer;
+ pdfi_countup(d);
code = pdfi_dict_get_type(ctx, ctx->Trailer, "Info", PDF_DICT, (pdf_obj **)&Info);
+ pdfi_countdown(d);
if (code < 0)
return code;
@@ -117,7 +122,7 @@ int pdfi_read_Info(pdf_context *ctx)
dmprintf(ctx->memory, "\n");
pdfi_device_set_flags(ctx);
- pdfi_write_docinfo_pdfmark(ctx, Info);
+ pdfi_pdfmark_write_docinfo(ctx, Info);
/* We don't pdfi_countdown(Info) now, because we've transferred our
* reference to the pointer in the pdf_context structure.
@@ -330,7 +335,7 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
goto errorExit;
pdfi_countup(Key);
- code = pdfi_dict_put_obj(ctx, leaf_dict, (pdf_obj *)Key, (pdf_obj *)node);
+ code = pdfi_dict_put_obj(ctx, leaf_dict, (pdf_obj *)Key, (pdf_obj *)node, true);
if (code < 0)
goto errorExit;
code = pdfi_dict_put(ctx, leaf_dict, "Type", (pdf_obj *)Key);
@@ -339,8 +344,15 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
code = pdfi_array_put(ctx, Kids, i, (pdf_obj *)leaf_dict);
if (code < 0)
goto errorExit;
+ leaf_dict = NULL;
}
} else {
+ if (ctx->loop_detection != NULL) {
+ if (node->object_num != 0 && pdfi_loop_detector_check_object(ctx, node->object_num)) {
+ code = gs_note_error(gs_error_circular_reference);
+ goto errorExit;
+ }
+ }
child = (pdf_dict *)node;
pdfi_countup(child);
}
@@ -349,6 +361,7 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
child = NULL;
errorExit:
+ pdfi_free_object((pdf_obj *)leaf_dict);
pdfi_countdown(child);
pdfi_countdown(node);
pdfi_countdown(Type);
@@ -496,15 +509,15 @@ int pdfi_get_page_dict(pdf_context *ctx, pdf_dict *d, uint64_t page_num, uint64_
} else {
if (pdfi_name_is(Type, "PageRef")) {
if ((*page_offset) == page_num) {
- pdf_dict *d = NULL;
+ pdf_dict *page_dict = NULL;
- code = pdfi_dict_get(ctx, child, "PageRef", (pdf_obj **)&d);
+ code = pdfi_dict_get(ctx, child, "PageRef", (pdf_obj **)&page_dict);
if (code < 0)
goto exit;
- code = pdfi_merge_dicts(ctx, d, inheritable);
- *target = d;
+ code = pdfi_merge_dicts(ctx, page_dict, inheritable);
+ *target = page_dict;
pdfi_countup(*target);
- pdfi_countdown(d);
+ pdfi_countdown(page_dict);
goto exit;
} else {
*page_offset += 1;
@@ -590,30 +603,45 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
*o = NULL;
- /* Check the provided dict */
- code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict);
- if (code < 0)
- goto exit;
- if (code > 0) {
- code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
- if (code != gs_error_undefined)
+ /* Check the provided dict, stream_dict can be NULL if we are trying to find a Default* ColorSpace */
+ if (dict != NULL) {
+ code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict);
+ if (code < 0)
goto exit;
- }
-
- /* Check the Parents, if any */
- code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
- if (code < 0)
- goto exit;
- if (code > 0) {
- if (Parent->object_num != ctx->page.CurrentPageDict->object_num) {
- code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o);
+ if (code > 0) {
+ code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
if (code != gs_error_undefined)
goto exit;
}
- }
- pdfi_countdown(typedict);
- typedict = NULL;
+ /* Check the Parents, if any */
+ code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
+ if (code < 0)
+ goto exit;
+ if (code > 0) {
+ if (Parent->object_num != ctx->page.CurrentPageDict->object_num) {
+ if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true)
+ return_error(gs_error_circular_reference);
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ code = pdfi_loop_detector_add_object(ctx, dict->object_num);
+ if (code < 0) {
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ return code;
+ }
+ code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o);
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ if (code != gs_error_undefined)
+ goto exit;
+ }
+ }
+
+ pdfi_countdown(typedict);
+ typedict = NULL;
+ }
/* Normally page_dict can't be (or shouldn't be) NULL. However, if we are processing
* a TYpe 3 font, then the 'page dict' is the Resources dictionary of that font. If
@@ -682,68 +710,10 @@ exit:
return code;
}
-/* Count how many children an outline entry has
- * This is separate just to keep the code from getting cluttered.
- */
-static int pdfi_doc_outline_count(pdf_context *ctx, pdf_dict *outline, int64_t *count)
-{
- int code = 0;
- pdf_dict *child = NULL;
- pdf_dict *Next = NULL;
-
- /* Handle this outline entry */
- code = pdfi_loop_detector_mark(ctx);
- if (code < 0)
- goto exit1;
-
- /* Count the children (don't deref them, we don't want to leave them hanging around) */
- code = pdfi_dict_get_no_store_R(ctx, outline, "First", (pdf_obj **)&child);
- if (code < 0 || child->type != PDF_DICT) {
- /* TODO: flag a warning? */
- code = 0;
- goto exit;
- }
-
- if (child->object_num != 0) {
- code = pdfi_loop_detector_add_object(ctx, child->object_num);
- if (code < 0)
- goto exit;
- }
-
- do {
- (*count) ++;
-
- code = pdfi_dict_get_no_store_R(ctx, child, "Next", (pdf_obj **)&Next);
- if (code == gs_error_circular_reference) {
- code = 0;
- goto exit;
- }
- if (code == gs_error_undefined) {
- code = 0;
- break;
- }
-
- if (code < 0 || Next->type != PDF_DICT)
- goto exit;
-
- pdfi_countdown(child);
- child = Next;
- } while (true);
-
- exit:
- (void)pdfi_loop_detector_cleartomark(ctx);
- exit1:
- pdfi_countdown(child);
- pdfi_countdown(Next);
- return code;
-}
-
/* Mark the actual outline */
static int pdfi_doc_mark_the_outline(pdf_context *ctx, pdf_dict *outline)
{
int code = 0;
- int64_t count = 0;
- int64_t numkids = 0;
pdf_dict *tempdict = NULL;
uint64_t dictsize;
uint64_t index;
@@ -752,19 +722,6 @@ static int pdfi_doc_mark_the_outline(pdf_context *ctx, pdf_dict *outline)
/* Basically we only do /Count, /Title, /A, /C, /F
* The /First, /Last, /Next, /Parent get written magically by pdfwrite
*/
- /* Count how many kids there are */
- code = pdfi_doc_outline_count(ctx, outline, &numkids);
-
- /* If no kids, see if there is a Count */
- if (numkids == 0) {
- code = pdfi_dict_get_int(ctx, outline, "Count", &count);
- if (code < 0 && code != gs_error_undefined)
- goto exit;
- if (count < 0)
- count = -count;
- } else {
- count = numkids;
- }
/* Make a temporary copy of the outline dict */
dictsize = pdfi_dict_entries(outline);
@@ -792,14 +749,9 @@ static int pdfi_doc_mark_the_outline(pdf_context *ctx, pdf_dict *outline)
*/
code = pdfi_dict_delete_pair(ctx, tempdict, Key);
} else if (pdfi_name_is(Key, "A")) {
- code = pdfi_mark_modA(ctx, tempdict);
+ code = pdfi_pdfmark_modA(ctx, tempdict);
} else if (pdfi_name_is(Key, "Dest")) {
- code = pdfi_mark_modDest(ctx, tempdict);
- } else if (pdfi_name_is(Key, "Count")) {
- /* Delete any count we find in the dict
- * We will use our value below
- */
- code = pdfi_dict_delete_pair(ctx, tempdict, Key);
+ code = pdfi_pdfmark_modDest(ctx, tempdict);
}
if (code < 0)
goto exit;
@@ -815,15 +767,8 @@ static int pdfi_doc_mark_the_outline(pdf_context *ctx, pdf_dict *outline)
}
if (code < 0) goto exit;
- /* If count is non-zero, put in dictionary */
- if (count != 0) {
- code = pdfi_dict_put_int(ctx, tempdict, "Count", count);
- if (code < 0)
- goto exit;
- }
-
/* Write the pdfmark */
- code = pdfi_mark_from_dict(ctx, tempdict, NULL, "OUT");
+ code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "OUT");
if (code < 0)
goto exit;
@@ -976,14 +921,18 @@ static int pdfi_doc_Outlines(pdf_context *ctx)
static int pdfi_doc_Info(pdf_context *ctx)
{
int code = 0;
- pdf_dict *Info = NULL;
+ pdf_dict *Info = NULL, *d = NULL;
pdf_dict *tempdict = NULL;
uint64_t dictsize;
uint64_t index;
pdf_name *Key = NULL;
pdf_obj *Value = NULL;
- code = pdfi_dict_knownget_type(ctx, ctx->Trailer, "Info", PDF_DICT, (pdf_obj **)&Info);
+ /* See comment in pdfi_read_Root() for details */
+ d = ctx->Trailer;
+ pdfi_countup(d);
+ code = pdfi_dict_knownget_type(ctx, d, "Info", PDF_DICT, (pdf_obj **)&Info);
+ pdfi_countdown(d);
if (code <= 0) {
/* TODO: flag a warning */
goto exit;
@@ -1003,7 +952,7 @@ static int pdfi_doc_Info(pdf_context *ctx)
if (pdfi_name_is(Key, "Author") || pdfi_name_is(Key, "Creator") ||
pdfi_name_is(Key, "Title") || pdfi_name_is(Key, "Subject") ||
pdfi_name_is(Key, "Keywords")) {
- code = pdfi_dict_put_obj(ctx, tempdict, (pdf_obj *)Key, Value);
+ code = pdfi_dict_put_obj(ctx, tempdict, (pdf_obj *)Key, Value, true);
if (code < 0)
goto exit;
}
@@ -1021,7 +970,7 @@ static int pdfi_doc_Info(pdf_context *ctx)
if (code < 0) goto exit;
/* Write the pdfmark */
- code = pdfi_mark_from_dict(ctx, tempdict, NULL, "DOCINFO");
+ code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCINFO");
exit:
pdfi_countdown(Key);
@@ -1037,14 +986,28 @@ static int pdfi_doc_PageLabels(pdf_context *ctx)
int code;
pdf_dict *PageLabels = NULL;
+ if (ctx->loop_detection) {
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+ }
+
code = pdfi_dict_knownget_type(ctx, ctx->Root, "PageLabels", PDF_DICT, (pdf_obj **)&PageLabels);
if (code <= 0) {
+ if (ctx->loop_detection)
+ (void)pdfi_loop_detector_cleartomark(ctx);
/* TODO: flag a warning */
goto exit;
}
+ if (ctx->loop_detection) {
+ code = pdfi_loop_detector_cleartomark(ctx);
+ if (code < 0)
+ goto exit;
+ }
+
/* This will send the PageLabels object as a 'pdfpagelabels' setdeviceparams */
- code = pdfi_mark_object(ctx, (pdf_obj *)PageLabels, "pdfpagelabels");
+ code = pdfi_pdfmark_object(ctx, (pdf_obj *)PageLabels, "pdfpagelabels");
if (code < 0)
goto exit;
@@ -1175,7 +1138,7 @@ static int pdfi_doc_EmbeddedFiles_Names(pdf_context *ctx, pdf_array *names)
code = pdfi_array_get_type(ctx, names, index+1, PDF_DICT, (pdf_obj **)&filespec);
if (code < 0) goto exit;
- code = pdfi_mark_embed_filespec(ctx, name, filespec);
+ code = pdfi_pdfmark_embed_filespec(ctx, name, filespec);
if (code < 0) goto exit;
pdfi_countdown(name);
diff --git a/pdf/pdf_errors.h b/pdf/pdf_errors.h
new file mode 100644
index 00000000..e52a6c74
--- /dev/null
+++ b/pdf/pdf_errors.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2022 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+#ifndef PARAM
+#define PARAM(A,B) A
+#endif
+PARAM(E_PDF_NOERROR, "no error"),
+PARAM(E_PDF_NOHEADER, "no header detected"),
+PARAM(E_PDF_NOHEADERVERSION, "header lacks a version number"),
+PARAM(E_PDF_NOSTARTXREF, "no startxref token found"),
+PARAM(E_PDF_BADSTARTXREF, "startxref offset invalid"),
+PARAM(E_PDF_BADXREFSTREAM, "couldn't read hybrid file's XrefStm"),
+PARAM(E_PDF_BADXREF, "error in xref table"),
+PARAM(E_PDF_SHORTXREF, "too few entries in xref table"),
+PARAM(E_PDF_MISSINGENDSTREAM, "content stream lacks endstream"),
+PARAM(E_PDF_UNKNOWNFILTER, "request for unknown filter"),
+PARAM(E_PDF_MISSINGWHITESPACE, "missing white space after number"),
+PARAM(E_PDF_MALFORMEDNUMBER, "malformed number"),
+PARAM(E_PDF_UNESCAPEDSTRING, "unbalanced or unescaped character '(' in string"),
+PARAM(E_PDF_BADOBJNUMBER, "invalid object number"),
+PARAM(E_PDF_MISSINGENDOBJ, "object lacks an endobj"),
+PARAM(E_PDF_TOKENERROR, "error executing PDF token"),
+PARAM(E_PDF_KEYWORDTOOLONG, "potential token is too long"),
+PARAM(E_PDF_BADPAGETYPE, "Page object doe snot have /Page type"),
+PARAM(E_PDF_CIRCULARREF, "circular reference to indirect object"),
+PARAM(E_PDF_UNREPAIRABLE, "couldn't repair PDF file"),
+PARAM(E_PDF_REPAIRED, "PDF file was repaired"),
+PARAM(E_PDF_BADSTREAM, "error reading a stream"),
+PARAM(E_PDF_MISSINGOBJ, "obj token missing"),
+PARAM(E_PDF_BADPAGEDICT, "error in Page dictionary"),
+PARAM(E_PDF_OUTOFMEMORY, "out of memory"),
+PARAM(E_PDF_PAGEDICTERROR, "error reading page dictionary"),
+PARAM(E_PDF_STACKUNDERFLOWERROR, "stack underflow"),
+PARAM(E_PDF_BADSTREAMDICT, "error in stream dictionary"),
+PARAM(E_PDF_INHERITED_STREAM_RESOURCE, "stream inherited a resource"),
+PARAM(E_PDF_DEREF_FREE_OBJ, "counting down reference to freed object"),
+PARAM(E_PDF_INVALID_TRANS_XOBJECT, "error in transparency XObject"),
+PARAM(E_PDF_NO_SUBTYPE, "object lacks a required Subtype"),
+PARAM(E_PDF_IMAGECOLOR_ERROR, "error in image colour"),
+PARAM(E_DICT_SELF_REFERENCE, "dictionary contains a key which (indirectly) references the dictionary."),
+PARAM(E_IMAGE_MASKWITHCOLOR, "Image has both ImageMask and ColorSpace keys."),
+PARAM(E_PDF_INVALID_DECRYPT_LEN, "Invalid /Length in Encryption dictionary (not in range 40-128 or not a multiple of 8)."),
+
+#undef PARAM
diff --git a/pdf/pdf_fapi.c b/pdf/pdf_fapi.c
index df92acc4..3e4420c4 100644
--- a/pdf/pdf_fapi.c
+++ b/pdf/pdf_fapi.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
@@ -550,7 +550,7 @@ pdfi_fapi_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, fl
break;
}
if (v->type == PDF_INT) {
- *ret = v->value.i;
+ *ret = (float)v->value.i;
}
else {
*ret = (float)v->value.d;
@@ -688,19 +688,24 @@ pdfi_fapi_get_gsubr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
}
else {
int leniv = (pfont->data.lenIV > 0 ? pfont->data.lenIV : 0);
- pdf_string *subrstring;
+ pdf_string *subrstring = NULL;
code = pdfi_array_get(pdffont2->ctx, pdffont2->GlobalSubrs, index, (pdf_obj **)&subrstring);
if (code >= 0) {
- code = subrstring->length - leniv;
- if (buf && buf_length >= code) {
- if (ff->need_decrypt && pfont->data.lenIV >= 0) {
- decode_bytes(buf, subrstring->data, code + leniv, pfont->data.lenIV);
- }
- else {
- memcpy(buf, subrstring->data, code);
+ if (subrstring->type == PDF_STRING) {
+ code = subrstring->length - leniv;
+ if (buf && buf_length >= code) {
+ if (ff->need_decrypt && pfont->data.lenIV >= 0) {
+ decode_bytes(buf, subrstring->data, code + leniv, pfont->data.lenIV);
+ }
+ else {
+ memcpy(buf, subrstring->data, code);
+ }
}
}
+ else {
+ code = gs_note_error(gs_error_invalidfont);
+ }
pdfi_countdown(subrstring);
}
}
@@ -746,19 +751,27 @@ pdfi_fapi_get_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
int leniv = (pfont->data.lenIV > 0 ? pfont->data.lenIV : 0);
pdf_string *subrstring;
- code = pdfi_array_get(pdffont2->ctx, pdffont2->Subrs, index, (pdf_obj **)&subrstring);
+ if (pdffont2->Subrs == NULL)
+ code = gs_note_error(gs_error_invalidfont);
+ else
+ code = pdfi_array_get(pdffont2->ctx, pdffont2->Subrs, index, (pdf_obj **)&subrstring);
if (code >= 0) {
- if (subrstring->length > 0) {
- code = subrstring->length - leniv;
- if (buf && buf_length >= code) {
- if (ff->need_decrypt && pfont->data.lenIV >= 0) {
- decode_bytes(buf, subrstring->data, code + leniv, pfont->data.lenIV);
- }
- else {
- memcpy(buf, subrstring->data, code);
+ if (subrstring->type == PDF_STRING) {
+ if (subrstring->length > 0) {
+ code = subrstring->length - leniv;
+ if (buf && buf_length >= code) {
+ if (ff->need_decrypt && pfont->data.lenIV >= 0) {
+ decode_bytes(buf, subrstring->data, code + leniv, pfont->data.lenIV);
+ }
+ else {
+ memcpy(buf, subrstring->data, code);
+ }
}
}
}
+ else {
+ code = gs_note_error(gs_error_invalidfont);
+ }
pdfi_countdown(subrstring);
}
}
@@ -914,7 +927,7 @@ pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_
else if (pbfont->FontType == ft_encrypted2) {
pdf_font_cff *cfffont = (pdf_font_cff *)pbfont->client_data;
pdf_name *glyphname = NULL;
- pdf_string *charstring = NULL;
+ pdf_string *charstr = NULL;
gs_const_string gname;
code = (*ctx->get_glyph_name)((gs_font *)pbfont, ccode, &gname);
@@ -928,22 +941,22 @@ pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_
pdfi_countdown(glyphname);
return code;
}
- code = pdfi_dict_get_by_key(cfffont->ctx, cfffont->CharStrings, glyphname, (pdf_obj **)&charstring);
+ code = pdfi_dict_get_by_key(cfffont->ctx, cfffont->CharStrings, glyphname, (pdf_obj **)&charstr);
pdfi_countdown(glyphname);
if (code < 0) {
- code = pdfi_dict_get(cfffont->ctx, cfffont->CharStrings, ".notdef", (pdf_obj **)&charstring);
+ code = pdfi_dict_get(cfffont->ctx, cfffont->CharStrings, ".notdef", (pdf_obj **)&charstr);
}
if (code < 0)
return code;
- I->ff.char_data = charstring->data;
- I->ff.char_data_len = charstring->length;
+ I->ff.char_data = charstr->data;
+ I->ff.char_data_len = charstr->length;
cr->client_char_code = 0;
cr->char_codes[0] = 0;
cr->is_glyph_index = true;
- pdfi_countdown(charstring);
+ pdfi_countdown(charstr);
return code;
}
else if (pbfont->FontType == ft_TrueType) {
@@ -1184,8 +1197,6 @@ pdfi_fapi_get_glyph(gs_fapi_font * ff, gs_glyph char_code, byte * buf, int buf_l
cstrlen = I->ff.char_data_len - leniv;
if (buf && buf_length >= cstrlen) {
- memcpy(buf, I->ff.char_data, I->ff.char_data_len);
-
if (ff->need_decrypt && pfont->data.lenIV >= 0)
decode_bytes(buf, I->ff.char_data, cstrlen + leniv, leniv);
else
@@ -1364,7 +1375,7 @@ static int
pdfi_fapi_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
gs_char chr, gs_glyph glyph)
{
- int code;
+ int code = 0;
gs_font_base *pbfont1;
gs_fapi_server *I;
@@ -1382,9 +1393,16 @@ pdfi_fapi_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
I->ff.client_font_data2 = cidpfont;
}
}
+ /* If between the font's creation and now another interpreter has driven FAPI (i.e. in a Postscript Begin/EndPage
+ context, the FAPI server data may end up set appropriately for the other interpreter, if that's happened, put
+ ours back before trying to interpret the glyph.
+ */
+ if (((gs_fapi_server *)pbfont1->FAPI)->ff.get_glyphname_or_cid != pdfi_fapi_get_glyphname_or_cid) {
+ code = pdfi_fapi_passfont((pdf_font *)pbfont1->client_data, 0, NULL, NULL, NULL, 0);
+ }
- code = gs_fapi_do_char((gs_font *)pbfont1, pgs, (gs_text_enum_t *) penum, NULL, false,
- NULL, NULL, chr, glyph, 0);
+ if (code >= 0)
+ code = gs_fapi_do_char((gs_font *)pbfont1, pgs, (gs_text_enum_t *) penum, NULL, false, NULL, NULL, chr, glyph, 0);
return (code);
}
@@ -1452,9 +1470,7 @@ pdfi_fapi_passfont(pdf_font *font, int subfont, char *fapi_request,
/* doesn't really matter for non-ttf */
*local_pdf_ff_stub.ttf_cmap_req = *nonsymbolic_req;
}
- /* The plfont should contain everything we need, but setting the client data for the server
- * to pbfont makes as much sense as setting it to NULL.
- */
+
gs_fapi_set_servers_client_data(pbfont->memory,
(const gs_fapi_font *)&local_pdf_ff_stub,
(gs_font *)pbfont);
diff --git a/pdf/pdf_file.c b/pdf/pdf_file.c
index 214d448d..5698866e 100644
--- a/pdf/pdf_file.c
+++ b/pdf/pdf_file.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -57,6 +57,8 @@
# include "sjpx.h"
#endif
+extern const uint file_default_buffer_size;
+
static void pdfi_close_filter_chain(pdf_context *ctx, stream *s, stream *target);
/* Utility routine to create a pdf_c_stream object */
@@ -102,6 +104,9 @@ pdfi_filter_open(uint buffer_size,
if (sst == NULL)
return_error(gs_error_VMerror);
}
+ if (buffer_size < 128)
+ buffer_size = file_default_buffer_size;
+
code = file_open_stream((char *)0, 0, "r", buffer_size, &s,
(gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
if (code < 0) {
@@ -232,7 +237,7 @@ int pdfi_apply_Arc4_filter(pdf_context *ctx, pdf_string *Key, pdf_c_stream *sour
stream *new_s;
int min_size = 2048;
- s_arcfour_set_key(&state, (const unsigned char *)Key->data, Key->length);
+ s_arcfour_set_key(&state, (const unsigned char *)Key->data, Key->length); /* lgtm [cpp/weak-cryptographic-algorithm] */
code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_arcfour_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s);
if (code < 0)
@@ -315,6 +320,7 @@ static int pdfi_Flate_filter(pdf_context *ctx, pdf_dict *d, stream *source, stre
stream_zlib_state zls;
uint min_size = 2048;
int code;
+ stream *Flate_source = NULL;
memset(&zls, 0, sizeof(zls));
@@ -329,9 +335,10 @@ static int pdfi_Flate_filter(pdf_context *ctx, pdf_dict *d, stream *source, stre
source = *new_stream;
if (d && d->type == PDF_DICT) {
+ Flate_source = (*new_stream)->strm;
code = pdfi_Predictor_filter(ctx, d, source, new_stream);
if (code < 0)
- pdfi_close_filter_chain(ctx, source, NULL);
+ pdfi_close_filter_chain(ctx, source, Flate_source);
}
return code;
}
@@ -344,7 +351,7 @@ pdfi_JBIG2Decode_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode,
uint min_size = s_jbig2decode_template.min_out_size;
int code;
pdf_stream *Globals = NULL;
- byte *buf;
+ byte *buf = NULL;
int64_t buflen;
void *globalctx;
@@ -367,8 +374,6 @@ pdfi_JBIG2Decode_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode,
goto cleanupExit;
s_jbig2decode_set_global_data((stream_state*)&state, NULL, globalctx);
-
- gs_free_object(ctx->memory, buf, "pdfi_JBIG2Decode_filter (Globals buf)");
}
}
}
@@ -383,6 +388,7 @@ pdfi_JBIG2Decode_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode,
code = 0;
cleanupExit:
+ gs_free_object(ctx->memory, buf, "pdfi_JBIG2Decode_filter (Globals buf)");
pdfi_countdown(Globals);
return code;
}
@@ -1058,6 +1064,9 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
if (ctx->encryption.is_encrypted && !inline_image) {
int64_t Length;
+ if (ctx->encryption.StmF == CRYPT_IDENTITY)
+ return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
+
code = pdfi_dict_get_type(ctx, stream_dict, "StreamKey", PDF_STRING, (pdf_obj **)&StreamKey);
if (code == gs_error_undefined) {
code = pdfi_compute_objkey(ctx, (pdf_obj *)stream_dict, &StreamKey);
@@ -1084,7 +1093,7 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
*/
Length = pdfi_stream_length(ctx, stream_obj);
- if (Length <= 0 || ctx->encryption.StrF == CRYPT_IDENTITY) {
+ if (Length <= 0) {
/* Don't treat as an encrypted stream if Length is 0 */
pdfi_countdown(StreamKey);
return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
@@ -1146,7 +1155,7 @@ error:
* NB! The EODString can't be tracked by the stream code. The caller is responsible for
* managing the lifetime of this object. It must remain valid until the filter is closed.
*/
-int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, pdf_string *EODString, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image)
+int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, const char *EODString, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image)
{
int code;
stream_SFD_state state;
@@ -1161,9 +1170,8 @@ int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, pdf_string *
s_SFD_template.set_defaults((stream_state *)&state);
if (EODString != NULL) {
- state.eod.data = EODString->data;
- state.eod.size = EODString->length;
- min_size = EODString->length;
+ state.eod.data = (const byte *)EODString;
+ state.eod.size = strlen(EODString);
}
if (EODCount > 0)
@@ -1176,6 +1184,12 @@ int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, pdf_string *
return code;
code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
+ if (code < 0) {
+ gs_free_object(ctx->memory->non_gc_memory, new_s->state, "pdfi_apply_SubFileDecode_filter");
+ gs_free_object(ctx->memory->non_gc_memory, new_s->cbuf, "pdfi_apply_SubFileDecode_filter");
+ gs_free_object(ctx->memory->non_gc_memory, new_s, "pdfi_apply_SubFileDecode_filter");
+ return code;
+ }
new_s->strm = source->s;
if (source->unread_size != 0) {
(*new_stream)->unread_size = source->unread_size;
@@ -1277,17 +1291,18 @@ int pdfi_open_memory_stream_from_filtered_stream(pdf_context *ctx, pdf_stream *s
code = pdfi_filter(ctx, stream_obj, compressed_stream, &decompressed_stream, false);
if (code < 0) {
pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream);
- gs_free_object(ctx->memory, *Buffer, "pdfi_open_memory_stream_from_filtered_stream");
*Buffer = NULL;
*new_pdf_stream = NULL;
return code;
}
do {
- byte b;
- code = pdfi_read_bytes(ctx, &b, 1, 1, decompressed_stream);
+ byte b[512];
+ code = pdfi_read_bytes(ctx, (byte *)&b, 1, 512, decompressed_stream);
if (code <= 0)
break;
- decompressed_length++;
+ decompressed_length+=code;
+ if (code < 512)
+ break;
} while (true);
pdfi_close_file(ctx, decompressed_stream);
@@ -1359,10 +1374,14 @@ int pdfi_open_memory_stream_from_memory(pdf_context *ctx, unsigned int size, byt
int pdfi_close_memory_stream(pdf_context *ctx, byte *Buffer, pdf_c_stream *source)
{
- sclose(source->s);
gs_free_object(ctx->memory, Buffer, "open memory stream(buffer)");
- gs_free_object(ctx->memory, source->s, "open memory stream(stream)");
- gs_free_object(ctx->memory, source, "open memory stream(pdf_stream)");
+ if (source != NULL) {
+ if (source->s != NULL) {
+ sclose(source->s);
+ gs_free_object(ctx->memory, source->s, "open memory stream(stream)");
+ }
+ gs_free_object(ctx->memory, source, "open memory stream(pdf_stream)");
+ }
return 0;
}
@@ -1418,25 +1437,58 @@ gs_offset_t pdfi_tell(pdf_c_stream *s)
return stell(s->s);
}
+int pdfi_unread_byte(pdf_context *ctx, pdf_c_stream *s, char c)
+{
+ if (s->unread_size == UNREAD_BUFFER_SIZE)
+ return_error(gs_error_ioerror);
+
+ s->unget_buffer[s->unread_size++] = c;
+
+ return 0;
+}
+
int pdfi_unread(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, uint32_t size)
{
if (size + s->unread_size > UNREAD_BUFFER_SIZE)
return_error(gs_error_ioerror);
- if (s->unread_size) {
- uint32_t index = s->unread_size - 1;
-
- do {
- s->unget_buffer[size + index] = s->unget_buffer[index];
- } while(index--);
+ Buffer += size;
+ while (size) {
+ s->unget_buffer[s->unread_size++] = *--Buffer;
+ size--;
}
- memcpy(s->unget_buffer, Buffer, size);
- s->unread_size += size;
-
return 0;
}
+int pdfi_read_byte(pdf_context *ctx, pdf_c_stream *s)
+{
+ int32_t code;
+
+ if (s->eof && s->unread_size == 0)
+ return EOFC;
+
+ if (s->unread_size)
+ return (byte)s->unget_buffer[--s->unread_size];
+
+ /* TODO the Ghostscript code uses sbufptr(s) to avoid a memcpy
+ * at some point we should modify this code to do so as well.
+ */
+ code = spgetc(s->s);
+ if (code == EOFC) {
+ s->eof = true;
+ return EOFC;
+ } else if (code == gs_error_ioerror) {
+ pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL);
+ s->eof = true;
+ return EOFC;
+ } else if(code == ERRC) {
+ return ERRC;
+ }
+ return (int)code;
+}
+
+
int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t count, pdf_c_stream *s)
{
uint32_t i = 0, total = size * count;
@@ -1447,38 +1499,32 @@ int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t coun
return 0;
if (s->unread_size) {
- if (s->unread_size >= total) {
- memcpy(Buffer, s->unget_buffer, total);
- for(i=0;i < s->unread_size - total;i++) {
- s->unget_buffer[i] = s->unget_buffer[i + total];
- }
- s->unread_size -= total;
- return total;
- } else {
- memcpy(Buffer, s->unget_buffer, s->unread_size);
- total -= s->unread_size;
- Buffer += s->unread_size;
- i = s->unread_size;
- s->unread_size = 0;
- if (s->eof)
- return i;
+ i = s->unread_size;
+ if (i >= total)
+ i = total;
+ bytes = i;
+ while (bytes) {
+ *Buffer++ = s->unget_buffer[--s->unread_size];
+ bytes--;
}
+ total -= i;
+ if (total == 0 || s->eof)
+ return i;
}
- if (total) {
- /* TODO the Ghostscript code uses sbufptr(s) to avoid a memcpy
- * at some point we should modify this code to do so as well.
- */
- code = sgets(s->s, Buffer, total, &bytes);
- if (code == EOFC) {
- s->eof = true;
- } else if (code == gs_error_ioerror) {
- pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL);
- s->eof = true;
- } else if(code == ERRC) {
- bytes = ERRC;
- } else {
- bytes = bytes + i;
- }
+
+ /* TODO the Ghostscript code uses sbufptr(s) to avoid a memcpy
+ * at some point we should modify this code to do so as well.
+ */
+ code = sgets(s->s, Buffer, total, &bytes);
+ if (code == EOFC) {
+ s->eof = true;
+ } else if (code == gs_error_ioerror) {
+ pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL);
+ s->eof = true;
+ } else if(code == ERRC) {
+ bytes = ERRC;
+ } else {
+ bytes = bytes + i;
}
return bytes;
@@ -1495,8 +1541,6 @@ pdfi_stream_to_buffer(pdf_context *ctx, pdf_stream *stream_obj, byte **buf, int6
byte *Buffer = NULL;
int code = 0;
int64_t buflen = 0;
- int bytes;
- char c;
gs_offset_t savedoffset;
pdf_c_stream *stream;
bool filtered;
@@ -1526,12 +1570,11 @@ pdfi_stream_to_buffer(pdf_context *ctx, pdf_stream *stream_obj, byte **buf, int6
if (code < 0) {
goto exit;
}
- /* Find out how big it is */
- do {
- bytes = sfread(&c, 1, 1, stream->s);
- if (bytes > 0)
- buflen++;
- } while (bytes >= 0);
+ while (seofp(stream->s) != true && serrorp(stream->s) != true) {
+ (void)sbufskip(stream->s, sbufavailable(stream->s));
+ s_process_read_buf(stream->s);
+ buflen += sbufavailable(stream->s);
+ }
pdfi_close_file(ctx, stream);
} else {
buflen = pdfi_stream_length(ctx, stream_obj);
@@ -1548,6 +1591,8 @@ pdfi_stream_to_buffer(pdf_context *ctx, pdf_stream *stream_obj, byte **buf, int6
goto exit;
if (filtered || ctx->encryption.is_encrypted) {
code = pdfi_filter(ctx, stream_obj, ctx->main_stream, &stream, false);
+ if (code < 0)
+ goto exit;
sfread(Buffer, 1, buflen, stream->s);
pdfi_close_file(ctx, stream);
} else {
diff --git a/pdf/pdf_file.h b/pdf/pdf_file.h
index a02d7f75..d1fafbb6 100644
--- a/pdf/pdf_file.h
+++ b/pdf/pdf_file.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -85,12 +85,14 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *d, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image);
void pdfi_close_file(pdf_context *ctx, pdf_c_stream *s);
int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t count, pdf_c_stream *s);
+int pdfi_read_byte(pdf_context *ctx, pdf_c_stream *s);
int pdfi_unread(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, uint32_t size);
+int pdfi_unread_byte(pdf_context *ctx, pdf_c_stream *s, char c);
int pdfi_seek(pdf_context *ctx, pdf_c_stream *s, gs_offset_t offset, uint32_t origin);
gs_offset_t pdfi_unread_tell(pdf_context *ctx);
gs_offset_t pdfi_tell(pdf_c_stream *s);
-int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, pdf_string *EODString, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image);
+int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, const char *EODString, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image);
int pdfi_open_memory_stream(pdf_context *ctx, unsigned int size, byte **Buffer, pdf_c_stream *source, pdf_c_stream **new_stream);
int pdfi_close_memory_stream(pdf_context *ctx, byte *Buffer, pdf_c_stream *source);
int pdfi_open_memory_stream_from_stream(pdf_context *ctx, unsigned int size, byte **Buffer, pdf_c_stream *source, pdf_c_stream **new_pdf_stream, bool retain_ownership);
diff --git a/pdf/pdf_fmap.c b/pdf/pdf_fmap.c
index 8fabb757..ee05af1c 100644
--- a/pdf/pdf_fmap.c
+++ b/pdf/pdf_fmap.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -20,9 +20,11 @@
#include "pdf_int.h"
#include "pdf_types.h"
+#include "pdf_array.h"
#include "pdf_dict.h"
#include "pdf_stack.h"
#include "pdf_file.h"
+#include "pdf_misc.h"
#include "pdf_fmap.h"
typedef struct
@@ -31,33 +33,44 @@ typedef struct
const char *mappedname;
} pdfi_custom_fmap_entry;
-pdfi_custom_fmap_entry pdfi_custom_fmap_enties[] =
+pdfi_custom_fmap_entry pdfi_custom_fmap_entries[] =
{
{"Helv", "Helvetica"},
{NULL, NULL}
};
+static inline bool pdfi_fmap_file_exists(pdf_context *ctx, pdf_string *fname)
+{
+ char nm[gp_file_name_sizeof];
+ struct stat buf;
+ int code = gs_error_invalidfileaccess;
+
+ if (fname->length < gp_file_name_sizeof) {
+ memcpy(nm, fname->data, fname->length);
+ nm[fname->length] = '\0';
+ code = gp_stat(ctx->memory, (const char *)nm, &buf);
+ }
+ return code >= 0;
+}
+
static int
-pdf_fontmap_open_file(pdf_context *ctx, byte **buf, int *buflen)
+pdf_fontmap_open_file(pdf_context *ctx, const char *mapfilename, byte **buf, int *buflen)
{
int code = 0;
stream *s;
char fname[gp_file_name_sizeof];
const char *path_pfx = "Init/";
- const char *fmap_default = "Fontmap.GS";
- const char *prestring = "<<\n";
- const char *poststring = ">>\nendstream\n";
- const int prestringlen = strlen(prestring);
+ const char *poststring = "\nendstream";
const int poststringlen = strlen(poststring);
fname[0] = '\0';
- if (strlen(path_pfx) + strlen(fmap_default) + 1 > gp_file_name_sizeof)
+ if (strlen(path_pfx) + strlen(mapfilename) + 1 > gp_file_name_sizeof)
return_error(gs_error_invalidfileaccess);
- code = pdfi_open_resource_file(ctx, fmap_default, strlen(fmap_default), &s);
+ code = pdfi_open_resource_file(ctx, mapfilename, strlen(mapfilename), &s);
if (code < 0) {
strncat(fname, path_pfx, strlen(path_pfx));
- strncat(fname, (char *)fmap_default, strlen(fmap_default));
+ strncat(fname, (char *)mapfilename, strlen(mapfilename));
code = pdfi_open_resource_file(ctx, fname, strlen(fname), &s);
}
@@ -66,14 +79,14 @@ pdf_fontmap_open_file(pdf_context *ctx, byte **buf, int *buflen)
sfseek(s, 0, SEEK_END);
*buflen = sftell(s);
sfseek(s, 0, SEEK_SET);
- *buf = gs_alloc_bytes(ctx->memory, *buflen + prestringlen + poststringlen, "pdf_cmap_open_file(buf)");
+ *buf = gs_alloc_bytes(ctx->memory, *buflen + poststringlen, "pdf_cmap_open_file(buf)");
if (*buf != NULL) {
- memcpy(*buf, prestring, prestringlen);
- sfread((*buf) + prestringlen, 1, *buflen, s);
- memcpy((*buf) + *buflen + prestringlen, poststring, poststringlen);
- *buflen += prestringlen + poststringlen;
+ sfread((*buf), 1, *buflen, s);
+ memcpy((*buf) + *buflen, poststring, poststringlen);
+ *buflen += poststringlen;
/* This is naff, but works for now
When parsing Fontmap in PS, ";" is defined as "def"
+ We don't need either, because the dictionary is built from the stack.
*/
for (i = 0; i < *buflen - 1; i++) {
if ((*buf)[i] == ';') {
@@ -90,53 +103,95 @@ pdf_fontmap_open_file(pdf_context *ctx, byte **buf, int *buflen)
}
static int
-pdf_make_fontmap(pdf_context *ctx)
+pdf_make_fontmap(pdf_context *ctx, const char *default_fmapname, int cidfmap)
{
byte *fmapbuf = NULL;
int code, fmapbuflen;
pdf_c_stream *fmapstr = NULL;
pdf_stream fakedict = {0};
- pdfi_custom_fmap_entry *pcfe = pdfi_custom_fmap_enties;
- int i;
-
+ pdfi_custom_fmap_entry *pcfe = pdfi_custom_fmap_entries;
+ int i, j = 0;
+ char fmapname[gp_file_name_sizeof];
pdf_c_stream fakemainstream = {0};
+ int stacksize = pdfi_count_stack(ctx);
+
+ strncpy(fmapname, default_fmapname, strlen(default_fmapname) + 1);
- code = pdf_fontmap_open_file(ctx, &fmapbuf, &fmapbuflen);
+ code = pdfi_mark_stack(ctx, PDF_DICT_MARK);
if (code < 0)
- return code;
+ goto done;
- code = pdfi_open_memory_stream_from_memory(ctx, fmapbuflen, fmapbuf, &fmapstr, true);
- if (code >= 0) {
- int stacksize = pdfi_count_stack(ctx);
+ do {
+ if (j < ctx->num_fontmapfiles) {
+ memcpy(fmapname, ctx->fontmapfiles[j].data, ctx->fontmapfiles[j].size);
+ fmapname[ctx->fontmapfiles[j].size] = '\0';
+ }
- if (ctx->main_stream == NULL) {
- ctx->main_stream = &fakemainstream;
+ code = pdf_fontmap_open_file(ctx, (const char *)fmapname, &fmapbuf, &fmapbuflen);
+ if (code < 0) {
+ if (ctx->args.QUIET != true) {
+ (void)outwrite(ctx->memory, "Warning: ", 9);
+ if (cidfmap)
+ (void)outwrite(ctx->memory, "cidfmap file ", 13);
+ else
+ (void)outwrite(ctx->memory, "Fontmap file \"", 14);
+ (void)outwrite(ctx->memory, fmapname, strlen(fmapname));
+ (void)outwrite(ctx->memory, "\" not found.\n", 13);
+ code = 0;
+ }
}
- code = pdfi_interpret_content_stream(ctx, fmapstr, &fakedict, NULL);
- if (ctx->main_stream == &fakemainstream) {
- ctx->main_stream = NULL;
+ else {
+ code = pdfi_open_memory_stream_from_memory(ctx, fmapbuflen, fmapbuf, &fmapstr, true);
+ if (code >= 0) {
+
+ if (ctx->main_stream == NULL) {
+ ctx->main_stream = &fakemainstream;
+ }
+
+ code = pdfi_interpret_content_stream(ctx, fmapstr, &fakedict, NULL);
+ if (ctx->main_stream == &fakemainstream) {
+ ctx->main_stream = NULL;
+ }
+ gs_free_object(ctx->memory, fmapbuf, "pdf_make_fontmap(fmapbuf)");
+ }
}
- if (pdfi_count_stack(ctx) > stacksize && ctx->stack_top[-1]->type == PDF_DICT) {
- ctx->pdffontmap = (pdf_dict *)ctx->stack_top[-1];
- pdfi_countup(ctx->pdffontmap);
+ j++;
+ } while(j < ctx->num_fontmapfiles && cidfmap == false && code >= 0);
+
+ if (code >= 0) {
+ if (pdfi_count_stack(ctx) > stacksize) {
+ code = pdfi_dict_from_stack(ctx, 0, 0, true);
+ if (code < 0)
+ goto done;
+
+ if (cidfmap == true) {
+ ctx->pdfcidfmap = (pdf_dict *)ctx->stack_top[-1];
+ pdfi_countup(ctx->pdfcidfmap);
+ }
+ else {
+ ctx->pdffontmap = (pdf_dict *)ctx->stack_top[-1];
+ pdfi_countup(ctx->pdffontmap);
+ }
pdfi_pop(ctx, 1);
code = 0;
/* Add our internal aliases to the fontmap. */
- for (i = 0; pcfe[i].keyname != NULL; i++) {
- pdf_obj *value;
- bool k;
-
- /* We don't want to *replace* entries */
- if (pdfi_dict_known(ctx, ctx->pdffontmap, pcfe[i].keyname, &k) >= 0
- && k != true) {
- code = pdfi_name_alloc(ctx, (byte *)pcfe[i].mappedname, strlen(pcfe[i].mappedname), &value);
- if (code < 0)
- continue;
- pdfi_countup(value);
- /* If dict_put throws an error, we just carry on - hence the (void) */
- (void)pdfi_dict_put(ctx, ctx->pdffontmap, pcfe[i].keyname, value);
- pdfi_countdown(value);
+ if (cidfmap == false) {
+ for (i = 0; pcfe[i].keyname != NULL; i++) {
+ pdf_obj *value;
+ bool k;
+
+ /* We don't want to *replace* entries */
+ if (pdfi_dict_known(ctx, ctx->pdffontmap, pcfe[i].keyname, &k) >= 0
+ && k != true) {
+ code = pdfi_name_alloc(ctx, (byte *)pcfe[i].mappedname, strlen(pcfe[i].mappedname), &value);
+ if (code < 0)
+ continue;
+ pdfi_countup(value);
+ /* If dict_put throws an error, we just carry on - hence the (void) */
+ (void)pdfi_dict_put(ctx, ctx->pdffontmap, pcfe[i].keyname, value);
+ pdfi_countdown(value);
+ }
}
}
}
@@ -144,38 +199,821 @@ pdf_make_fontmap(pdf_context *ctx)
code = gs_note_error(gs_error_syntaxerror);
}
}
- gs_free_object(ctx->memory, fmapbuf, "pdf_make_fontmap(fmapbuf)");
+done:
+ /* We always want to leave here with a valid map dictionary
+ even if it's empty
+ */
+ if (cidfmap == true) {
+ if (ctx->pdfcidfmap == NULL) {
+ code = pdfi_dict_alloc(ctx, 0, &ctx->pdfcidfmap);
+ pdfi_countup(ctx->pdfcidfmap);
+ }
+ }
+ else {
+ if (ctx->pdffontmap == NULL) {
+ code = pdfi_dict_alloc(ctx, 0, &ctx->pdffontmap);
+ pdfi_countup(ctx->pdffontmap);
+ }
+ }
+ pdfi_clearstack(ctx);
+ return code;
+}
+
+enum {
+ no_type_font = -1,
+ type0_font = 0,
+ type1_font = 1,
+ cff_font = 2,
+ type3_font = 3,
+ tt_font = 42
+};
+
+/* For font file scanning we want to treat OTTO as TTF (rather than, for "normal"
+ font loading, treat OTTO as CFF, hence we need a different type picker.
+ */
+static int pdfi_font_scan_type_picker(byte *buf, int64_t buflen)
+{
+#define MAKEMAGIC(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+ if (buflen >= 4) {
+ if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC(0, 1, 0, 0)
+ || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 'r', 'u', 'e')
+ || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 't', 'c', 'f')) {
+ return tt_font;
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('O', 'T', 'T', 'O')) {
+ return tt_font;
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC('%', '!', 'P', 0)) {
+ return type1_font; /* pfa */
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC(1, 0, 4, 0)) {
+ return cff_font; /* 1C/CFF */
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], 0, 0) == MAKEMAGIC(128, 1, 0, 0)) {
+ return type1_font; /* pfb */
+ }
+ }
+ return no_type_font;
+#undef MAKEMAGIC
+}
+
+static int pdfi_add__to_native_fontmap(pdf_context *ctx, const char *fontname, const char *filepath, const int index)
+{
+ int code;
+ pdf_string *fpstr;
+
+ if (ctx->pdfnativefontmap == NULL) {
+ /* 32 is just an arbitrary starting point */
+ code = pdfi_dict_alloc(ctx, 32, &ctx->pdfnativefontmap);
+ if (code < 0)
+ return code;
+ pdfi_countup(ctx->pdfnativefontmap);
+ }
+ /* index == -1 is a file with a single font in it */
+ if (index == -1) {
+ code = pdfi_object_alloc(ctx, PDF_STRING, strlen(filepath), (pdf_obj **)&fpstr);
+ if (code < 0)
+ return code;
+ pdfi_countup(fpstr);
+ memcpy(fpstr->data, filepath, fpstr->length);
+ code = pdfi_dict_put(ctx, ctx->pdfnativefontmap, fontname, (pdf_obj *)fpstr);
+ pdfi_countdown(fpstr);
+ }
+ else {
+ pdf_dict *recdict;
+ pdf_num *ind;
+
+ code = pdfi_object_alloc(ctx, PDF_DICT, 2, (pdf_obj **)&recdict);
+ if (code < 0)
+ return code;
+ pdfi_countup(recdict);
+
+ code = pdfi_object_alloc(ctx, PDF_STRING, strlen(filepath), (pdf_obj **)&fpstr);
+ if (code < 0) {
+ pdfi_countdown(recdict);
+ return code;
+ }
+ pdfi_countup(fpstr);
+ memcpy(fpstr->data, filepath, fpstr->length);
+ code = pdfi_dict_put(ctx, recdict, "Path", (pdf_obj *)fpstr);
+ pdfi_countdown(fpstr);
+ if (code < 0) {
+ pdfi_countdown(recdict);
+ return code;
+ }
+
+ code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&ind);
+ if (code < 0) {
+ pdfi_countdown(recdict);
+ return code;
+ }
+ ind->value.i = index;
+ pdfi_countup(ind);
+ code = pdfi_dict_put(ctx, recdict, "Index", (pdf_obj *)ind);
+ pdfi_countdown(ind);
+ if (code < 0) {
+ pdfi_countdown(recdict);
+ return code;
+ }
+ code = pdfi_dict_put(ctx, ctx->pdfnativefontmap, fontname, (pdf_obj *)recdict);
+ pdfi_countdown(recdict);
+ }
+
return code;
}
+static inline int
+pdfi_end_ps_token(int c)
+{
+ return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA) || (c == '/') || (c == '\0');
+}
+
+/* Naive way to find a Type 1 /FontName key */
+static int pdfi_type1_add_to_native_map(pdf_context *ctx, stream *f, char *fname, char *pname, int pname_size)
+{
+ gs_string buf;
+ uint count = 0;
+ int code = gs_error_undefined;
+ char *namestr = NULL, *enamestr;
+ char *typestr;
+ bool pin_eol = false; /* initialised just to placate coverity */
+ int type = -1;
+ buf.data = (byte *)pname;
+ buf.size = pname_size;
+
+ /* It's not an absolute requirement, but it is a de facto standard that
+ /FontType and /FontName keys start in column 0 of their lines
+ */
+ while ((code = sreadline(f, NULL, NULL, NULL, &buf, NULL, &count, &pin_eol, NULL)) >= 0) {
+ if (buf.size > 9 && memcmp(buf.data, "/FontName", 9) == 0) {
+ namestr = (char *)buf.data + 9;
+ while (pdfi_end_ps_token(*namestr))
+ namestr++;
+ if (*namestr != '\0') {
+ while(*namestr == 0x20 || *namestr == 0x9)
+ namestr++;
+ if (*namestr == '/')
+ namestr++;
+ enamestr = namestr;
+ while(!pdfi_end_ps_token((int)*enamestr))
+ enamestr++;
+ count = enamestr - namestr > pname_size - 1 ? pname_size - 1 : enamestr - namestr;
+ memcpy(pname, namestr, count);
+ pname[count] = '\0';
+ buf.data += count + 1;
+ buf.size -= count + 1;
+ if (type == 1)
+ break;
+ }
+ }
+ else if (buf.size > 9 && memcmp(buf.data, "/FontType", 9) == 0) {
+ typestr = (char *)buf.data + 9;
+ while (pdfi_end_ps_token(*typestr))
+ typestr++;
+ if (*typestr != '\0') {
+ while(*typestr == 0x20 || *typestr == 0x9)
+ namestr++;
+ if (*typestr == '/')
+ typestr++;
+ enamestr = typestr;
+ while(!pdfi_end_ps_token((int)*enamestr))
+ enamestr++;
+ count = enamestr - typestr > pname_size - 1 ? pname_size - 1 : enamestr - typestr;
+ if (count == 1 && *typestr == '1') {
+ type = 1;
+ if (namestr != NULL)
+ break;
+ }
+ }
+ }
+ else if (buf.size >= 17 && memcmp(buf.data, "currentfile eexec", 17) == 0)
+ break;
+ count = 0;
+ }
+ if (type == 1 && namestr != NULL) {
+ code = pdfi_add__to_native_fontmap(ctx, (const char *)pname, (const char *)fname, -1);
+ }
+ return code < 0 ? code : gs_error_handled;
+}
+
+static inline int
+u16(const byte *p)
+{
+ return (p[0] << 8) | p[1];
+}
+
+static inline int
+sru16(stream *s)
+{
+ byte p[2];
+ int code = sfread(p, 1, 2, s);
+
+ if (code < 0)
+ return 0;
+
+ return u16(p);
+}
+
+static inline int
+u32(const byte *p)
+{
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static inline int
+sru32(stream *s)
+{
+ byte p[4];
+ int code = sfread(p, 1, 4, s);
+ if (code < 0)
+ return 0;
+
+ return u32(p);
+}
+
+static int pdfi_ttf_add_to_native_map(pdf_context *ctx, stream *f, byte magic[4], char *fname, char *pname, int pname_size)
+{
+ int ntables, i, j, k, code2, code = gs_error_undefined;
+ char table[4];
+ int nte, storageOffset;
+ bool include_index = false;
+ uint32_t nfonts = 1, tableoffs;
+ int findex;
+ gs_offset_t l;
+
+ code2 = sfseek(f, 0, SEEK_END);
+ if (code2 < 0)
+ return code;
+ l = stell(f);
+ /* 4 to skip the magic number */
+ code2 = sfseek(f, 4, SEEK_SET);
+ if (code2 < 0)
+ return code;
+
+ if (memcmp(magic, "ttcf", 4) == 0) {
+ uint32_t ver;
+ include_index = true;
+ ver = sru32(f);
+ if (ver != 0x00010000 && ver !=0x00020000) {
+ dmprintf1(ctx->memory, "Unknown TTC header version %08X.\n", ver);
+ return_error(gs_error_invalidaccess);
+ }
+ nfonts = sru32(f);
+ /* There isn't a specific limit on the number of fonts,
+ freetype limits to 255, so we'll do the same here
+ */
+ if (nfonts > 255)
+ return_error(gs_error_invalidfont);
+ }
+
+ for (findex = 0; findex < nfonts; findex++) {
+ if (include_index == true ) {
+ if (findex * 4 > l)
+ break;
+ code2 = sfseek(f, findex * 4, SEEK_CUR);
+ if (code2 < 0)
+ return code2;
+
+ tableoffs = sru32(f);
+ if (tableoffs + 4 > l)
+ break;
+ code2 = sfseek(f, tableoffs + 4, SEEK_SET);
+ if (code2 < 0)
+ return code2;
+ }
+
+ ntables = sru16(f);
+ /* Similar to above - no spec limit, but we do the same
+ as freetype
+ */
+ if (ntables > 255)
+ continue;
+
+ /* Skip the remainder of the invariant header bytes */
+ (void)sru16(f);
+ (void)sru32(f);
+
+ for (i = 0, code2 = 0; i < ntables && code2 >= 0; i++) {
+ if (stell(f) + 4 > l) {
+ code2 = gs_error_ioerror;
+ continue;
+ }
+ code2 = sfread(table, 1, 4, f);
+ if (code2 < 0)
+ return code2;
+ if (!memcmp(table, "name", 4)) {
+ uint table_pos, table_len;
+ byte *namet;
+ (void)sru32(f); /* skip checksum */
+
+ table_pos = sru32(f);
+ table_len = sru32(f);
+ if (table_pos + table_len > l) {
+ code2 = gs_error_ioerror;
+ continue;
+ }
+
+ code2 = sfseek(f, table_pos, SEEK_SET);
+ if (code2 < 0)
+ continue;
+
+ namet = (byte *)gs_alloc_bytes(ctx->memory, table_len, "pdfi_ttf_add_to_native_map");
+ if (namet == NULL)
+ return_error(gs_error_VMerror);
+ code2 = sfread(namet, 1, table_len, f);
+ if (code2 < 0) {
+ gs_free_object(ctx->memory, namet,"pdfi_ttf_add_to_native_map");
+ continue;
+ }
+ nte = u16(namet + 2);
+ /* Again, arbitrary limit... */
+ if (nte > 255) {
+ gs_free_object(ctx->memory, namet,"pdfi_ttf_add_to_native_map");
+ continue;
+ }
+ storageOffset = u16(namet + 4);
+
+ for (j = 0; j < nte; j++) {
+ byte *rec = namet + 6 + j * 12;
+ if (u16(rec + 6) == 6) {
+ int nl = u16(rec + 8);
+ int noffs = u16(rec + 10);
+ if (nl + noffs + storageOffset > table_len) {
+ break;
+ }
+ memcpy(pname, namet + storageOffset + noffs, nl);
+ pname[nl] = '\0';
+ for (k = 0; k < nl; k++)
+ if (pname[k] < 32 || pname[k] > 126) /* is it a valid name? */
+ break;
+ if (k == nl) {
+ code = 0;
+ break;
+ }
+ }
+ }
+ if (code == gs_error_undefined) {
+ for (j = 0; j < nte; j++) {
+ byte *rec = namet + 6 + j * 12;
+ if (u16(rec + 6) == 4) {
+ int nl = u16(rec + 8);
+ int noffs = u16(rec + 10);
+ if (nl + noffs + storageOffset > table_len) {
+ break;
+ }
+ memcpy(pname, namet + storageOffset + noffs, nl);
+ pname[nl] = '\0';
+ for (k = 0; k < nl; k++)
+ if (pname[k] < 32 || pname[k] > 126) /* is it a valid name? */
+ break;
+ if (k == nl)
+ code = 0;
+ break;
+ }
+ }
+ }
+ gs_free_object(ctx->memory, namet, "pdfi_ttf_add_to_native_map");
+ break;
+ }
+ else {
+ sfseek(f, 12, SEEK_CUR);
+ }
+ }
+ if (code >= 0)
+ code = pdfi_add__to_native_fontmap(ctx, (const char *)pname, (const char *)fname, (include_index == true ? findex : -1));
+ }
+ return code;
+}
+
+static const char *font_scan_skip_list[] = {
+ ".afm",
+ ".bat",
+ ".c",
+ ".cmd",
+ ".com",
+ ".dir",
+ ".dll",
+ ".doc",
+ ".drv",
+ ".exe",
+ ".fon",
+ ".fot",
+ ".h",
+ ".o",
+ ".obj",
+ ".pfm",
+ ".pss",
+ ".txt",
+ ".gz",
+ ".pcf"
+};
+
+static bool font_scan_skip_file(char *fname)
+{
+ size_t l2, l = strlen(fname);
+ bool skip = false;
+ int i;
+
+ for (i = 0; i < (sizeof(font_scan_skip_list)/sizeof(*font_scan_skip_list)); i++) {
+ l2 = strlen(font_scan_skip_list[i]);
+ if (memcmp(font_scan_skip_list[i], fname + l - l2, l2) == 0) {
+ skip = true;
+ break;
+ }
+ }
+ return skip;
+}
+
+static int pdfi_generate_native_fontmap(pdf_context *ctx)
+{
+ file_enum *fe;
+ int i;
+ char *patrn= NULL;
+ char *result = NULL;
+ char *working = NULL;
+ byte magic[4]; /* We only (currently) use up to 4 bytes for type guessing */
+ stream *sf;
+ int code = 0, l;
+ uint nread;
+
+ if (ctx->pdfnativefontmap != NULL) /* Only run this once */
+ return 0;
+ if (ctx->args.nonativefontmap == true) {
+ /* Basically create an empty dictionary */
+ code = pdfi_dict_alloc(ctx, 1, &ctx->pdfnativefontmap);
+ if (code < 0)
+ return code;
+ pdfi_countup(ctx->pdfnativefontmap);
+ return 0;
+ }
+
+ patrn = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
+ result = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
+ working = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
+ if (patrn == NULL || result == NULL || working == NULL) {
+ gs_free_object(ctx->memory, patrn, "pdfi_generate_native_fontmap");
+ gs_free_object(ctx->memory, result, "pdfi_generate_native_fontmap");
+ gs_free_object(ctx->memory, working, "pdfi_generate_native_fontmap");
+ return_error(gs_error_VMerror);
+ }
+
+ for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
+
+ memcpy(patrn, ctx->search_paths.font_paths[i].data, ctx->search_paths.font_paths[i].size);
+ memcpy(patrn + ctx->search_paths.font_paths[i].size, "/*", 2);
+ patrn[ctx->search_paths.font_paths[i].size + 2] = '\0';
+
+ fe = gp_enumerate_files_init(ctx->memory, (const char *)patrn, strlen(patrn));
+ while ((l = gp_enumerate_files_next(ctx->memory, fe, result, gp_file_name_sizeof - 1)) != ~(uint) 0) {
+ int type;
+ result[l] = '\0';
+
+ if (font_scan_skip_file(result))
+ continue;
+
+ sf = sfopen(result, "r", ctx->memory);
+ code = sgets(sf, magic, 4, &nread);
+ if (code < 0 || nread < 4) {
+ sfclose(sf);
+ continue;
+ }
+
+ code = sfseek(sf, 0, SEEK_SET);
+ if (code < 0) {
+ sfclose(sf);
+ continue;
+ }
+ /* Slightly naff: in this one case, we want to treat OTTO fonts
+ as Truetype, so we lookup the TTF 'name' table - it's more efficient
+ than decoding the CFF, and probably will give more expected results
+ */
+ if (memcmp(magic, "OTTO", 4) == 0 || memcmp(magic, "ttcf", 4) == 0) {
+ type = tt_font;
+ }
+ else {
+ type = pdfi_font_scan_type_picker((byte *)magic, 4);
+ }
+ switch(type) {
+ case tt_font:
+ code = pdfi_ttf_add_to_native_map(ctx, sf, magic, result, working, gp_file_name_sizeof);
+ break;
+ case cff_font:
+ code = gs_error_undefined;
+ break;
+ case type1_font:
+ default:
+ code = pdfi_type1_add_to_native_map(ctx, sf, result, working, gp_file_name_sizeof);
+ break;
+ }
+ sfclose(sf);
+ /* We ignore most errors, on the basis it probably means it wasn't a valid font file */
+ if (code == gs_error_VMerror)
+ break;
+ code = 0;
+ }
+ /* We only need to explicitly destroy the enumerator if we exit before enumeration is complete */
+ if (code < 0)
+ gp_enumerate_files_close(ctx->memory, fe);
+ }
+
+#if 0
+ if (ctx->pdfnativefontmap != NULL) {
+ uint64_t ind;
+ int find = -1;
+ pdf_name *key = NULL;
+ pdf_obj *v = NULL;
+ pdf_string *val = NULL;
+ (void)pdfi_dict_key_first(ctx, ctx->pdfnativefontmap, (pdf_obj **) &key, &ind);
+ (void)pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, key, (pdf_obj **)&v);
+ for (j = 0; j < key->length; j++)
+ dprintf1("%c", key->data[j]);
+ if (v->type == PDF_DICT) {
+ pdf_num *n;
+ pdf_string *val2;
+ code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
+ if (code >= 0 && n->type == PDF_INT)
+ find = n->value.i;
+ else
+ code = 0;
+ (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
+ val = val2;
+ }
+ else {
+ val = (pdf_string *)v;
+ }
+ dprintf(" ");
+ for (j = 0; j < val->length; j++)
+ dprintf1("%c", val->data[j]);
+ if (find != -1) {
+ dprintf1(" Index = %d", find);
+ find = -1;
+ }
+
+ dprintf("\n");
+ pdfi_countdown(key);
+ pdfi_countdown(val);
+
+ while (pdfi_dict_key_next(ctx, ctx->pdfnativefontmap, (pdf_obj **) &key, &ind) >= 0 && ind > 0) {
+ (void)pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, key, (pdf_obj **)&v);
+ for (j = 0; j < key->length; j++)
+ dprintf1("%c", key->data[j]);
+ if (v->type == PDF_DICT) {
+ pdf_num *n;
+ pdf_string *val2;
+ code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
+ if (code >= 0 && n->type == PDF_INT)
+ find = n->value.i;
+ else
+ code = 0;
+ (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
+ val = val2;
+ }
+ else {
+ val = (pdf_string *)v;
+ }
+ dprintf(" ");
+ for (j = 0; j < val->length; j++)
+ dprintf1("%c", val->data[j]);
+ if (find != -1) {
+ dprintf1(" Index = %d", find);
+ find = -1;
+ }
+ pdfi_countdown(key);
+ pdfi_countdown(val);
+ dprintf("\n");
+ }
+ }
+#endif
+
+ gs_free_object(ctx->memory, patrn, "pdfi_generate_native_fontmap");
+ gs_free_object(ctx->memory, result, "pdfi_generate_native_fontmap");
+ gs_free_object(ctx->memory, working, "pdfi_generate_native_fontmap");
+ return 0;
+}
int
-pdf_fontmap_lookup_font(pdf_context *ctx, pdf_name *fname, pdf_obj **mapname)
+pdf_fontmap_lookup_font(pdf_context *ctx, pdf_name *fname, pdf_obj **mapname, int *findex)
{
- int code = 0;
+ int code;
pdf_obj *mname;
+ *findex = -1;
+
if (ctx->pdffontmap == NULL) {
- code = pdf_make_fontmap(ctx);
+ const char *fmap_default = "Fontmap.GS";
+ char *fmapname = (char *)fmap_default;
+ code = pdf_make_fontmap(ctx, fmapname, false);
if (code < 0) {
return code;
}
}
+ if (ctx->pdfnativefontmap == NULL) {
+ code = pdfi_generate_native_fontmap(ctx);
+ if (code < 0)
+ return code;
+ }
+
code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, fname, &mname);
+ if (code >= 0) {
+ /* Fontmap can map in multiple "jump" i.e.
+ name -> substitute name
+ subsitute name -> file name
+ So we want to loop until we no more hits.
+ */
+ while(1) {
+ pdf_obj *mname2;
+ code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, (pdf_name *)mname, &mname2);
+ if (code < 0) break;
+ pdfi_countdown(mname);
+ mname = mname2;
+ }
+ }
+ else if (ctx->pdfnativefontmap != NULL) {
+ pdf_obj *record;
+ code = pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, fname, &record);
+ if (code < 0)
+ return code;
+ if (record->type == PDF_STRING) {
+ mname = record;
+ }
+ else {
+ pdf_num *ind;
+ code = pdfi_dict_get(ctx, (pdf_dict *)record, "Path", &mname);
+ if (code < 0) {
+ pdfi_countdown(record);
+ return code;
+ }
+ code = pdfi_dict_get(ctx, (pdf_dict *)record, "Index", (pdf_obj **)&ind);
+ if (code >= 0 && ind->type == PDF_INT) {
+ *findex = ind->value.i;
+ }
+ }
+ }
+
+ if (mname != NULL && mname->type == PDF_STRING && pdfi_fmap_file_exists(ctx, (pdf_string *)mname)) {
+ *mapname = mname;
+ code = 0;
+ }
+ else if (mname != NULL && mname->type == PDF_NAME) { /* If we map to a name, we assume (for now) we have the font as a "built-in" */
+ *mapname = mname;
+ code = 0;
+ }
+ else {
+ pdfi_countdown(mname);
+ code = gs_note_error(gs_error_undefined);
+ }
+ return code;
+}
+
+int
+pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name, pdf_obj **mapname, int *findex)
+{
+ int code = 0;
+ pdf_obj *cidname = NULL;
+ pdf_obj *mname;
+
+ if (ctx->pdfcidfmap == NULL) {
+ const char *cidfmap_default = "cidfmap";
+ char *cidfmapname = (char *)cidfmap_default;
+ code = pdf_make_fontmap(ctx, cidfmapname, true);
+ if (code < 0) {
+ return code;
+ }
+ }
+ if (name == NULL || name->type != PDF_NAME) {
+ code = pdfi_dict_get(ctx, font_dict, "BaseFont", &cidname);
+ if (code < 0 || cidname->type != PDF_NAME) {
+ pdfi_countdown(cidname);
+ return_error(gs_error_undefined);
+ }
+
+ }
+ else {
+ cidname = (pdf_obj *)name;
+ pdfi_countup(cidname);
+ }
+
+ code = pdfi_dict_get_by_key(ctx, ctx->pdfcidfmap, (pdf_name *)cidname, &mname);
+ pdfi_countdown(cidname);
if (code < 0)
return code;
- /* Fontmap can map in multiple "jump" i.e.
+ /* As above cidfmap can map in multiple "jump" i.e.
name -> substitute name
- subsitute name -> file name
+ subsitute name -> "record"
So we want to loop until we no more hits.
*/
while(1) {
pdf_obj *mname2;
- code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, (pdf_name *)mname, &mname2);
+ code = pdfi_dict_get_by_key(ctx, ctx->pdfcidfmap, (pdf_name *)mname, &mname2);
if (code < 0) break;
pdfi_countdown(mname);
mname = mname2;
}
- *mapname = mname;
- return 0;
+ if (mname->type == PDF_DICT) {
+ pdf_dict *rec = (pdf_dict *)mname;
+ pdf_name *filetype;
+ pdf_name *path = NULL;
+ pdf_num *ind = NULL;
+ pdf_array *mcsi = NULL;
+ pdf_dict *ocsi = NULL;
+ pdf_string *ord1 = NULL, *ord2 = NULL;
+ pdf_num *sup1, *sup2;
+
+ code = pdfi_dict_get(ctx, rec, "FileType", (pdf_obj **)&filetype);
+ /* We only handle TTF files, just now */
+ if (code < 0 || filetype->type != PDF_NAME || filetype->length != 8 || memcmp(filetype->data, "TrueType", 8) != 0) {
+ pdfi_countdown(filetype);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ pdfi_countdown(filetype);
+
+ code = pdfi_dict_get(ctx, rec, "CSI", (pdf_obj **)&mcsi);
+ if (code < 0 || mcsi->type != PDF_ARRAY) {
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+
+ code = pdfi_dict_get(ctx, font_dict, "CIDSystemInfo", (pdf_obj **)&ocsi);
+ if (code < 0 || ocsi->type != PDF_DICT) {
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ code = pdfi_dict_get(ctx, ocsi, "Ordering", (pdf_obj **)&ord1);
+ if (code < 0 || ord1->type != PDF_STRING) {
+ pdfi_countdown(ord1);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ code = pdfi_array_get(ctx, mcsi, 0, (pdf_obj **)&ord2);
+ if (code < 0 || ord2->type != PDF_STRING) {
+ pdfi_countdown(ord1);
+ pdfi_countdown(ord2);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ if (pdfi_string_cmp(ord1, ord2) != 0) {
+ pdfi_countdown(ord1);
+ pdfi_countdown(ord2);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ pdfi_countdown(ord1);
+ pdfi_countdown(ord2);
+ code = pdfi_dict_get(ctx, ocsi, "Supplement", (pdf_obj **)&sup1);
+ if (code < 0 || sup1->type != PDF_INT) {
+ pdfi_countdown(ord1);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ code = pdfi_array_get(ctx, mcsi, 1, (pdf_obj **)&sup2);
+ if (code < 0 || sup2->type != PDF_INT || sup1->value.i != sup2->value.i) {
+ pdfi_countdown(sup1);
+ pdfi_countdown(sup2);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+ pdfi_countdown(sup1);
+ pdfi_countdown(sup2);
+ pdfi_countdown(ocsi);
+ pdfi_countdown(mcsi);
+
+ code = pdfi_dict_get(ctx, rec, "Path", (pdf_obj **)&path);
+ if (code < 0 || path->type != PDF_STRING || !pdfi_fmap_file_exists(ctx, (pdf_string *)path)) {
+ pdfi_countdown(rec);
+ return_error(gs_error_undefined);
+ }
+
+ *mapname = (pdf_obj *)path;
+ code = pdfi_dict_get(ctx, rec, "Index", (pdf_obj **)&ind);
+ if (code >= 0 && ind->type != PDF_INT) {
+ *findex = ind->value.i;
+ }
+ else {
+ *findex = 0;
+ }
+ pdfi_countdown(ind);
+ code = 0;
+
+ }
+ else {
+ *mapname = (pdf_obj *)mname;
+ code = 0;
+ }
+
+ return code;
}
diff --git a/pdf/pdf_fmap.h b/pdf/pdf_fmap.h
index 602bb0cf..c7650203 100644
--- a/pdf/pdf_fmap.h
+++ b/pdf/pdf_fmap.h
@@ -17,4 +17,10 @@
or might be a string.
*/
int
-pdf_fontmap_lookup_font(pdf_context *ctx, pdf_name *fname, pdf_obj **mapname);
+pdf_fontmap_lookup_font(pdf_context *ctx, pdf_name *fname, pdf_obj **mapname, int *findex);
+
+/* The name parameter is to allow for internally derived font names to be looked up,
+ like, for example, /Adobe-Japan1
+ */
+int
+pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name, pdf_obj **mapname, int *findex);
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index 7fa8a427..fa716056 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -16,6 +16,8 @@
/* Font operations for the PDF interpreter */
#include "pdf_int.h"
+#include "pdf_font_types.h"
+#include "pdf_gstate.h"
#include "pdf_file.h"
#include "pdf_dict.h"
#include "pdf_loop_detect.h"
@@ -24,7 +26,6 @@
#include "pdf_stack.h"
#include "pdf_misc.h"
#include "pdf_doc.h"
-#include "pdf_font_types.h"
#include "pdf_font0.h"
#include "pdf_font1.h"
#include "pdf_font1C.h"
@@ -41,12 +42,15 @@
static int pdfi_gs_setfont(pdf_context *ctx, gs_font *pfont)
{
int code = 0;
- pdf_font *old_font = pdfi_get_current_pdf_font(ctx);
+ pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
+ pdf_font *old_font = igs->current_font;
code = gs_setfont(ctx->pgs, pfont);
- if (code >= 0)
+ if (code >= 0) {
+ igs->current_font = (pdf_font *)pfont->client_data;
+ pdfi_countup(igs->current_font);
pdfi_countdown(old_font);
-
+ }
return code;
}
@@ -145,6 +149,19 @@ pdfi_font_match_glyph_widths(pdf_font *pdfont)
return code;
}
+/* Print a name object to stdout */
+static void pdfi_print_font_name(pdf_context *ctx, pdf_name *n)
+{
+ if (ctx->args.QUIET != true)
+ (void)outwrite(ctx->memory, (const char *)n->data, n->length);
+}
+
+/* Print a null terminated string to stdout */
+static void pdfi_print_string(pdf_context *ctx, const char *str)
+{
+ if (ctx->args.QUIET != true)
+ (void)outwrite(ctx->memory, str, strlen(str));
+}
/* Call with a CIDFont name to try to find the CIDFont on disk
call if with ffname NULL to load the default fallback CIDFont
@@ -152,25 +169,179 @@ pdfi_font_match_glyph_widths(pdf_font *pdfont)
Currently only loads subsitute - DroidSansFallback
*/
static int
-pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_dict *fontdesc, bool fallback, byte ** buf, int64_t * buflen)
+pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_dict *fontdesc, bool fallback, byte ** buf, int64_t * buflen, int *findex)
{
- int code = gs_error_invalidfont;
+ int code = 0;
+ char fontfname[gp_file_name_sizeof];
+ stream *s;
+ pdf_name *cidname = NULL;
+ gs_const_string fname;
+
+ (void)pdfi_dict_get(ctx, font_dict, "BaseFont", (pdf_obj **)&cidname);
if (fallback == true) {
- char fontfname[gp_file_name_sizeof];
- const char *fsprefix = "CIDFSubst/";
+ pdf_string *mname = NULL;
+ pdf_dict *csi = NULL;
+
+ code = pdfi_dict_get(ctx, font_dict, "CIDSystemInfo", (pdf_obj **)&csi);
+ if (code >= 0 && csi->type == PDF_DICT) {
+ pdf_string *csi_reg = NULL, *csi_ord = NULL;
+
+ if (pdfi_dict_get(ctx, csi, "Registry", (pdf_obj **)&csi_reg) >= 0
+ && pdfi_dict_get(ctx, csi, "Ordering", (pdf_obj **)&csi_ord) >= 0
+ && csi_reg->type == PDF_STRING && csi_ord->type == PDF_STRING
+ && csi_reg->length + csi_ord->length + 1 < gp_file_name_sizeof - 1) {
+ pdf_name *reg_ord;
+ memcpy(fontfname, csi_reg->data, csi_reg->length);
+ memcpy(fontfname + csi_reg->length, "-", 1);
+ memcpy(fontfname + csi_reg->length + 1, csi_ord->data, csi_ord->length);
+ fontfname[csi_reg->length + csi_ord->length + 1] = '\0';
+
+ code = pdfi_name_alloc(ctx, (byte *)fontfname, strlen(fontfname), (pdf_obj **) &reg_ord);
+ if (code >= 0) {
+ pdfi_countup(reg_ord);
+ code = pdf_fontmap_lookup_cidfont(ctx, font_dict, reg_ord, (pdf_obj **)&mname, findex);
+ pdfi_countdown(reg_ord);
+ }
+ }
+ pdfi_countdown(csi_reg);
+ pdfi_countdown(csi_ord);
+ }
+ pdfi_countdown(csi);
+
+ if (mname == NULL || mname->type != PDF_STRING)
+ code = pdf_fontmap_lookup_cidfont(ctx, font_dict, NULL, (pdf_obj **)&mname, findex);
+
+ if (code < 0 || mname->type != PDF_STRING) {
+ const char *fsprefix = "CIDFSubst/";
+ int fsprefixlen = strlen(fsprefix);
+ const char *defcidfallack = "DroidSansFallback.ttf";
+ int defcidfallacklen = strlen(defcidfallack);
+
+ pdfi_countdown(mname);
+
+ if (ctx->args.nocidfallback == true) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
+ if (ctx->args.cidsubstpath.data == NULL) {
+ memcpy(fontfname, fsprefix, fsprefixlen);
+ }
+ else {
+ memcpy(fontfname, ctx->args.cidsubstpath.data, ctx->args.cidsubstpath.size);
+ fsprefixlen = ctx->args.cidsubstpath.size;
+ }
+
+ if (ctx->args.cidsubstfont.data == NULL) {
+ int len = 0;
+ if (gp_getenv("CIDSUBSTFONT", (char *)0, &len) < 0 && len + fsprefixlen + 1 < gp_file_name_sizeof) {
+ (void)gp_getenv("CIDSUBSTFONT", (char *)(fontfname + fsprefixlen), &defcidfallacklen);
+ }
+ else {
+ memcpy(fontfname + fsprefixlen, defcidfallack, defcidfallacklen);
+ }
+ }
+ else {
+ memcpy(fontfname, ctx->args.cidsubstfont.data, ctx->args.cidsubstfont.size);
+ defcidfallacklen = ctx->args.cidsubstfont.size;
+ }
+ fontfname[fsprefixlen + defcidfallacklen] = '\0';
+
+ code = pdfi_open_resource_file(ctx, fontfname, strlen(fontfname), &s);
+ if (code < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
+ if (cidname) {
+ pdfi_print_string(ctx, "Loading CIDFont ");
+ pdfi_print_font_name(ctx, (pdf_name *)cidname);
+ pdfi_print_string(ctx, " substitute from ");
+ }
+ else {
+ pdfi_print_string(ctx, "Loading nameless CIDFont from ");
+ }
+ sfilename(s, &fname);
+ if (fname.size < gp_file_name_sizeof) {
+ memcpy(fontfname, fname.data, fname.size);
+ fontfname[fname.size] = '\0';
+ }
+ else {
+ strcpy(fontfname, "unnamed file");
+ }
+ pdfi_print_string(ctx, fontfname);
+ pdfi_print_string(ctx, "\n");
+
+
+ sfseek(s, 0, SEEK_END);
+ *buflen = sftell(s);
+ sfseek(s, 0, SEEK_SET);
+ *buf = gs_alloc_bytes(ctx->memory, *buflen, "pdfi_open_CIDFont_file(buf)");
+ if (*buf != NULL) {
+ sfread(*buf, 1, *buflen, s);
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ }
+ sfclose(s);
+ }
+ }
+ }
+ else {
+ code = pdfi_open_resource_file(ctx, (const char *)mname->data, mname->length, &s);
+ pdfi_countdown(mname);
+ if (code < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
+ if (cidname) {
+ pdfi_print_string(ctx, "Loading CIDFont ");
+ pdfi_print_font_name(ctx, (pdf_name *)cidname);
+ pdfi_print_string(ctx, " (or substitute) from ");
+ }
+ else {
+ pdfi_print_string(ctx, "Loading nameless CIDFont from ");
+ }
+ sfilename(s, &fname);
+ if (fname.size < gp_file_name_sizeof) {
+ memcpy(fontfname, fname.data, fname.size);
+ fontfname[fname.size] = '\0';
+ }
+ else {
+ strcpy(fontfname, "unnamed file");
+ }
+ pdfi_print_string(ctx, fontfname);
+ pdfi_print_string(ctx, "\n");
+ sfseek(s, 0, SEEK_END);
+ *buflen = sftell(s);
+ sfseek(s, 0, SEEK_SET);
+ *buf = gs_alloc_bytes(ctx->memory, *buflen, "pdfi_open_CIDFont_file(buf)");
+ if (*buf != NULL) {
+ sfread(*buf, 1, *buflen, s);
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ }
+ sfclose(s);
+ }
+ }
+ }
+ else {
+ const char *fsprefix = "CIDFont/";
const int fsprefixlen = strlen(fsprefix);
- const char *defcidfallack = "DroidSansFallback.ttf";
- const int defcidfallacklen = strlen(defcidfallack);
- stream *s;
- code = 0;
+
+ if (cidname == NULL || cidname->type != PDF_NAME
+ || fsprefixlen + cidname->length >= gp_file_name_sizeof)
+ goto exit;
memcpy(fontfname, fsprefix, fsprefixlen);
- memcpy(fontfname + fsprefixlen, defcidfallack, defcidfallacklen);
- fontfname[fsprefixlen + defcidfallacklen] = '\0';
+ memcpy(fontfname + fsprefixlen, cidname->data, cidname->length);
+ fontfname[fsprefixlen + cidname->length] = '\0';
code = pdfi_open_resource_file(ctx, fontfname, strlen(fontfname), &s);
- if (code >= 0) {
+ if (code < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
sfseek(s, 0, SEEK_END);
*buflen = sftell(s);
sfseek(s, 0, SEEK_SET);
@@ -179,14 +350,15 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
sfread(*buf, 1, *buflen, s);
}
else {
- code = gs_note_error(gs_error_VMerror);
+ code = gs_note_error(gs_error_invalidfont);
}
sfclose(s);
}
}
- else {
- code = gs_error_invalidfont;
- }
+
+exit:
+ if (cidname != NULL)
+ pdfi_countdown(cidname);
return code;
}
@@ -316,16 +488,44 @@ static const char *pdfi_font_substitute_by_flags(unsigned int flags)
return "Helvetica"; /* Really shouldn't ever happen */
}
-static void pdfi_emprint_font_name(pdf_context *ctx, pdf_name *n)
+enum {
+ no_type_font = -1,
+ type0_font = 0,
+ type1_font = 1,
+ cff_font = 2,
+ type3_font = 3,
+ tt_font = 42
+};
+
+static int pdfi_fonttype_picker(byte *buf, int64_t buflen)
{
- int i;
- for (i = 0; i < n->length; i++) {
- dmprintf1(ctx->memory, "%c", n->data[i]);
+#define MAKEMAGIC(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+ if (buflen >= 4) {
+ if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC(0, 1, 0, 0)
+ || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 'r', 'u', 'e')
+ || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 't', 'c', 'f')) {
+ return tt_font;
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('O', 'T', 'T', 'O')) {
+ return cff_font; /* OTTO will end up as CFF */
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC('%', '!', 'P', 0)) {
+ return type1_font; /* pfa */
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC(1, 0, 4, 0)) {
+ return cff_font; /* 1C/CFF */
+ }
+ else if (MAKEMAGIC(buf[0], buf[1], 0, 0) == MAKEMAGIC(128, 1, 0, 0)) {
+ return type1_font; /* pfb */
+ }
}
+ return no_type_font;
+#undef MAKEMAGIC
}
static int
-pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *fontdesc, bool fallback, byte **buf, int64_t *buflen)
+pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *fontdesc, bool fallback, byte **buf, int64_t *buflen, int *findex)
{
int code;
char fontfname[gp_file_name_sizeof];
@@ -335,7 +535,7 @@ pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *
const char *fn;
code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
- if (code < 0 || ((pdf_name *)basefont)->length == 0)
+ if (code < 0 || basefont == NULL || ((pdf_name *)basefont)->length == 0)
fallback = true;
if (fallback == true) {
@@ -368,40 +568,51 @@ pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *
pdfi_countup(fontname);
}
}
- code = pdf_fontmap_lookup_font(ctx, (pdf_name *) fontname, &mapname);
+ code = pdf_fontmap_lookup_font(ctx, (pdf_name *) fontname, &mapname, findex);
if (code < 0) {
mapname = fontname;
pdfi_countup(mapname);
code = 0;
}
- if (mapname->type == PDF_NAME) {
+ if (mapname->type == PDF_NAME || mapname->type == PDF_STRING) {
pdf_name *mname = (pdf_name *) mapname;
if (mname->length + 1 < gp_file_name_sizeof) {
memcpy(fontfname, mname->data, mname->length);
fontfname[mname->length] = '\0';
}
else {
+ pdfi_countdown(mapname);
+ pdfi_countdown(fontname);
return_error(gs_error_invalidfileaccess);
}
}
+ else {
+ pdfi_countdown(mapname);
+ pdfi_countdown(fontname);
+ return_error(gs_error_invalidfileaccess);
+ }
code = pdfi_open_font_file(ctx, fontfname, strlen(fontfname), &s);
if (code >= 0) {
gs_const_string fname;
if (basefont) {
- dmprintf(ctx->memory, "Loading font ");
- pdfi_emprint_font_name(ctx, (pdf_name *)basefont);
- dmprintf(ctx->memory, " (or substitute) from ");
+ pdfi_print_string(ctx, "Loading font ");
+ pdfi_print_font_name(ctx, (pdf_name *)basefont);
+ pdfi_print_string(ctx, " (or substitute) from ");
}
else {
- dmprintf(ctx->memory, "Loading nameless font from ");
+ pdfi_print_string(ctx, "Loading nameless font from ");
}
sfilename(s, &fname);
if (fname.size < gp_file_name_sizeof) {
memcpy(fontfname, fname.data, fname.size);
fontfname[fname.size] = '\0';
}
- dmprintf1(ctx->memory, "%s.\n", fontfname);
+ else {
+ strcpy(fontfname, "unnamed file");
+ }
+ pdfi_print_string(ctx, fontfname);
+ pdfi_print_string(ctx, "\n");
sfseek(s, 0, SEEK_END);
*buflen = sftell(s);
@@ -423,42 +634,6 @@ pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *
}
enum {
- no_type_font = -1,
- type0_font = 0,
- type1_font = 1,
- cff_font = 2,
- type3_font = 3,
- tt_font = 42
-};
-
-static int pdfi_fonttype_picker(byte *buf, int64_t buflen)
-{
-#define MAKEMAGIC(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-
- if (buflen >= 4) {
- if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC(0, 1, 0, 0)
- || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 'r', 'u', 'e')
- || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 't', 'c', 'f')) {
- return tt_font;
- }
- else if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('O', 'T', 'T', 'O')) {
- return cff_font; /* OTTO will end up as CFF */
- }
- else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC('%', '!', 'P', 0)) {
- return type1_font; /* pfa */
- }
- else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC(1, 0, 4, 0)) {
- return cff_font; /* 1C/CFF */
- }
- else if (MAKEMAGIC(buf[0], buf[1], 0, 0) == MAKEMAGIC(128, 1, 0, 0)) {
- return type1_font; /* pfb */
- }
- }
- return no_type_font;
-#undef MAKEMAGIC
-}
-
-enum {
font_embedded = 0,
font_from_file = 1,
font_substitute = 2
@@ -477,6 +652,7 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
byte *fbuf = NULL;
int64_t fbuflen;
int substitute = font_embedded;
+ int findex = -1;
code = pdfi_dict_get_type(ctx, font_dict, "Type", PDF_NAME, (pdf_obj **)&Type);
if (code < 0)
@@ -489,7 +665,12 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
/* Beyond Type 0 and Type 3, there is no point trusting the Subtype key */
if (code >= 0 && pdfi_name_is(Subtype, "Type0")) {
- code = pdfi_read_type0_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, &ppdffont);
+ if (cidfont == true) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
+ code = pdfi_read_type0_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, &ppdffont);
+ }
}
else if (code >= 0 && pdfi_name_is(Subtype, "Type3")) {
code = pdfi_read_type3_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, &ppdffont);
@@ -549,7 +730,8 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
if (fftype != no_type_font)
sftype = fftype;
else {
- if (pdfi_name_is(Subtype, "Type1") || pdfi_name_is(Subtype, "MMType1"))
+ /* If we don't have a Subtype, can't work it out, try Type 1 */
+ if (Subtype == NULL || pdfi_name_is(Subtype, "Type1") || pdfi_name_is(Subtype, "MMType1"))
sftype = type1_font;
else if (pdfi_name_is(Subtype, "Type1C"))
sftype = cff_font;
@@ -570,18 +752,22 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
case tt_font:
{
if (cidfont)
- code = pdfi_read_cidtype2_font(ctx, font_dict, stream_dict, page_dict, fbuf, fbuflen, &ppdffont);
+ code = pdfi_read_cidtype2_font(ctx, font_dict, stream_dict, page_dict, fbuf, fbuflen, findex, &ppdffont);
else
- code = pdfi_read_truetype_font(ctx, font_dict, stream_dict, page_dict, fbuf, fbuflen, &ppdffont);
+ code = pdfi_read_truetype_font(ctx, font_dict, stream_dict, page_dict, fbuf, fbuflen, findex, &ppdffont);
fbuf = NULL;
}
break;
default:
code = gs_note_error(gs_error_invalidfont);
}
+
if (code < 0 && substitute == font_embedded) {
- dmprintf2(ctx->memory, "**** Error: can't process embedded stream for font object %d %d.\n", font_dict->object_num, font_dict->generation_num);
- dmprintf(ctx->memory, "**** Attempting to load substitute font.\n");
+ char obj[129];
+ pdfi_print_string(ctx, "**** Warning: cannot process embedded stream for font object ");
+ gs_snprintf(obj, 128, "%d %d\n", (int)font_dict->object_num, (int)font_dict->generation_num);
+ pdfi_print_string(ctx, obj);
+ pdfi_print_string(ctx, "**** Attempting to load a substitute font.\n");
}
}
@@ -594,9 +780,9 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
substitute = font_from_file;
if (cidfont == true) {
- code = pdfi_open_CIDFont_substitute_file(ctx, font_dict, fontdesc, false, &fbuf, &fbuflen);
+ code = pdfi_open_CIDFont_substitute_file(ctx, font_dict, fontdesc, false, &fbuf, &fbuflen, &findex);
if (code < 0) {
- code = pdfi_open_CIDFont_substitute_file(ctx, font_dict, fontdesc, true, &fbuf, &fbuflen);
+ code = pdfi_open_CIDFont_substitute_file(ctx, font_dict, fontdesc, true, &fbuf, &fbuflen, &findex);
substitute |= font_substitute;
}
@@ -604,9 +790,9 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
goto exit;
}
else {
- code = pdfi_open_font_substitute_file(ctx, font_dict, fontdesc, false, &fbuf, &fbuflen);
+ code = pdfi_open_font_substitute_file(ctx, font_dict, fontdesc, false, &fbuf, &fbuflen, &findex);
if (code < 0) {
- code = pdfi_open_font_substitute_file(ctx, font_dict, fontdesc, true, &fbuf, &fbuflen);
+ code = pdfi_open_font_substitute_file(ctx, font_dict, fontdesc, true, &fbuf, &fbuflen, &findex);
substitute |= font_substitute;
}
@@ -646,6 +832,7 @@ int pdfi_load_dict_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_
{
int code;
gs_font *pfont;
+ pdf_font *pdfif;
if (font_dict->type == PDF_FONT) {
pdfi_countup(font_dict);
@@ -666,10 +853,8 @@ int pdfi_load_dict_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_
if (pfont != ctx->pgs->font) {
code = pdfi_gs_setfont(ctx, pfont);
}
- else {
- pdf_font *pdfif = (pdf_font *)pfont->client_data;
- pdfi_countdown(pdfif);
- }
+ pdfif = (pdf_font *)pfont->client_data;
+ pdfi_countdown(pdfif);
if (code < 0)
goto exit;
@@ -984,6 +1169,8 @@ int pdfi_d0(pdf_context *ctx)
if (ctx->text.inside_CharProc == false)
pdfi_set_warning(ctx, 0, NULL, W_PDF_NOTINCHARPROC, "pdfi_d0", NULL);
+ ctx->text.CharProc_d_type = pdf_type3_d0;
+
if (pdfi_count_stack(ctx) < 2) {
code = gs_note_error(gs_error_stackunderflow);
goto d0_error;
@@ -1064,9 +1251,9 @@ int pdfi_d1(pdf_context *ctx)
if (ctx->text.inside_CharProc == false)
pdfi_set_warning(ctx, 0, NULL, W_PDF_NOTINCHARPROC, "pdfi_d1", NULL);
- ctx->text.CharProc_is_d1 = true;
+ ctx->text.CharProc_d_type = pdf_type3_d1;
- if (pdfi_count_stack(ctx) < 2) {
+ if (pdfi_count_stack(ctx) < 6) {
code = gs_note_error(gs_error_stackunderflow);
goto d1_error;
}
@@ -1188,6 +1375,29 @@ int pdfi_free_font(pdf_obj *font)
return 0;
}
+static inline int pdfi_encoding_name_to_index(pdf_name *name)
+{
+ int ind = gs_error_undefined;
+ if (name->type == PDF_NAME) {
+ if (pdfi_name_is(name, "StandardEncoding")) {
+ ind = ENCODING_INDEX_STANDARD;
+ } else {
+ if (pdfi_name_is(name, "WinAnsiEncoding")){
+ ind = ENCODING_INDEX_WINANSI;
+ } else {
+ if (pdfi_name_is(name, "MacRomanEncoding")){
+ ind = ENCODING_INDEX_MACROMAN;
+ } else {
+ if (pdfi_name_is(name, "MacExpertEncoding")){
+ ind = ENCODING_INDEX_MACEXPERT;
+ }
+ }
+ }
+ }
+ }
+ return ind;
+}
+
/*
* Routine to fill in an array with each of the glyph names from a given
* 'standard' Encoding.
@@ -1203,25 +1413,13 @@ static int pdfi_build_Encoding(pdf_context *ctx, pdf_name *name, pdf_array *Enco
if (pdfi_array_size(Encoding) < 256)
return gs_note_error(gs_error_rangecheck);
- if (pdfi_name_is(name, "StandardEncoding")) {
- gs_encoding = ENCODING_INDEX_STANDARD;
- } else {
- if (pdfi_name_is(name, "WinAnsiEncoding")){
- gs_encoding = ENCODING_INDEX_WINANSI;
- } else {
- if (pdfi_name_is(name, "MacRomanEncoding")){
- gs_encoding = ENCODING_INDEX_MACROMAN;
- } else {
- if (pdfi_name_is(name, "MacExpertEncoding")){
- gs_encoding = ENCODING_INDEX_MACEXPERT;
- } else {
- return_error(gs_error_undefined);
- }
- }
- }
- }
- i = 0;
- for (i=0;i<256;i++) {
+ code = pdfi_encoding_name_to_index(name);
+ if (code < 0)
+ return code;
+ gs_encoding = (unsigned char)code;
+ code = 0;
+
+ for (i = 0;i<256;i++) {
temp = gs_c_known_encode(i, gs_encoding);
gs_c_glyph_name(temp, &str);
code = pdfi_name_alloc(ctx, (byte *)str.data, str.size, (pdf_obj **)&n);
@@ -1284,6 +1482,18 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
}
else {
code = pdfi_dict_get(ctx, (pdf_dict *)pdf_Encoding, "BaseEncoding", (pdf_obj **)&n);
+ if (code >= 0) {
+ if (pdfi_encoding_name_to_index(n) < 0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_FONT_BASEENC, "pdfi_create_Encoding", NULL);
+ pdfi_countdown(n);
+ n = NULL;
+ code = gs_error_undefined;
+ }
+ else if (pdfi_name_is(n, "StandardEncoding") == true) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_FONT_BASEENC, "pdfi_create_Encoding", NULL);
+ }
+ }
+
if (code < 0) {
code = pdfi_name_alloc(ctx, (byte *)"StandardEncoding", 16, (pdf_obj **)&n);
if (code < 0) {
@@ -1293,6 +1503,7 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
}
pdfi_countup(n);
}
+
code = pdfi_build_Encoding(ctx, n, (pdf_array *)*Encoding);
if (code < 0) {
pdfi_countdown(*Encoding);
@@ -1375,11 +1586,81 @@ gs_glyph pdfi_encode_char(gs_font * pfont, gs_char chr, gs_glyph_space_t not_use
return g;
}
+int pdfi_tounicode_char_to_unicode(pdf_context *ctx, pdf_cmap *tounicode, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length)
+{
+ int i, l = 0;
+ int code = gs_error_undefined;
+ unsigned char *ucode = (unsigned char *)unicode_return;
+
+ if (tounicode != NULL) {
+ gs_cmap_lookups_enum_t lenum;
+ gs_cmap_lookups_enum_init((const gs_cmap_t *)tounicode->gscmap, 0, &lenum);
+ while (l == 0 && (code = gs_cmap_enum_next_lookup(ctx->memory, &lenum)) == 0) {
+ gs_cmap_lookups_enum_t counter = lenum;
+ while (l == 0 && (code = gs_cmap_enum_next_entry(&counter) == 0)) {
+ if (counter.entry.value_type == CODE_VALUE_CID) {
+ unsigned int v = 0;
+ for (i = 0; i < counter.entry.key_size; i++) {
+ v |= (counter.entry.key[0][counter.entry.key_size - i - 1]) << (i * 8);
+ }
+ if (ch == v) {
+ if (counter.entry.value.size == 1) {
+ l = 2;
+ if (ucode != NULL && length >= l) {
+ ucode[0] = counter.entry.value.data[0];
+ ucode[1] = counter.entry.value.data[1];
+ }
+ }
+ else if (counter.entry.value.size == 2) {
+ l = 2;
+ if (ucode != NULL && length >= l) {
+ ucode[0] = counter.entry.value.data[0];
+ ucode[1] = counter.entry.value.data[1];
+ }
+ }
+ else if (counter.entry.value.size == 3) {
+ l = 4;
+ if (ucode != NULL && length >= l) {
+ ucode[0] = counter.entry.value.data[0];
+ ucode[1] = counter.entry.value.data[1];
+ ucode[2] = counter.entry.value.data[2];
+ ucode[3] = 0;
+ }
+ }
+ else {
+ l = 4;
+ if (ucode != NULL && length >= l) {
+ ucode[0] = counter.entry.value.data[0];
+ ucode[1] = counter.entry.value.data[1];
+ ucode[2] = counter.entry.value.data[1];
+ ucode[3] = counter.entry.value.data[3];
+ }
+ }
+ }
+ }
+ }
+ }
+ if (l > 0)
+ code = l;
+ }
+
+ return code;
+}
+
/* Get the unicode valude for a glyph FIXME - not written yet
*/
int pdfi_decode_glyph(gs_font * font, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length)
{
- return 0;
+ pdf_font *pdffont = (pdf_font *)font->client_data;
+ int code = 0;
+
+ if (pdffont->pdfi_font_type != e_pdf_cidfont_type0 && pdffont->pdfi_font_type != e_pdf_cidfont_type1
+ && pdffont->pdfi_font_type != e_pdf_cidfont_type2 && pdffont->pdfi_font_type != e_pdf_cidfont_type4) {
+ code = pdfi_tounicode_char_to_unicode(pdffont->ctx, (pdf_cmap *)pdffont->ToUnicode, glyph, ch, unicode_return, length);
+ }
+ if (code < 0) code = 0;
+
+ return code;
}
int pdfi_glyph_index(gs_font *pfont, byte *str, uint size, uint *glyph)
@@ -1562,8 +1843,7 @@ static int pdfi_font_set_internal_inner(pdf_context *ctx, const byte *fontname,
code = pdfi_set_font_internal(ctx, font, point_size);
exit:
- if (code < 0)
- pdfi_countdown(font); /* Keep the ref if succeeded */
+ pdfi_countdown(font);
return code;
}
diff --git a/pdf/pdf_font.h b/pdf/pdf_font.h
index 381ba729..da76aeb8 100644
--- a/pdf/pdf_font.h
+++ b/pdf/pdf_font.h
@@ -61,6 +61,7 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
gs_glyph pdfi_encode_char(gs_font * pfont, gs_char chr, gs_glyph_space_t not_used);
int pdfi_glyph_index(gs_font *pfont, byte *str, uint size, uint *glyph);
int pdfi_glyph_name(gs_font * pfont, gs_glyph glyph, gs_const_string * pstr);
+int pdfi_tounicode_char_to_unicode(pdf_context *ctx, pdf_cmap *tounicode, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length);
int pdfi_decode_glyph(gs_font * font, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length);
/* This is in pdf_fapi.c, but since it is the only exported function
diff --git a/pdf/pdf_font0.c b/pdf/pdf_font0.c
index 86baec8d..a322bfb4 100644
--- a/pdf/pdf_font0.c
+++ b/pdf/pdf_font0.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
@@ -77,7 +77,6 @@ pdfi_font0_map_glyph_to_unicode(gs_font *font, gs_glyph glyph, int ch, ushort *u
int code = gs_error_undefined, i;
uchar *unicode_return = (uchar *)u;
pdf_cidfont_type2 *decfont = NULL;
- pdf_cmap *tounicode = (pdf_cmap *)pt0font->ToUnicode;
pdfi_cid_subst_nwp_table_t *substnwp = pt0font->substnwp;
code = pdfi_array_get(pt0font->ctx, pt0font->DescendantFonts, 0, (pdf_obj **)&decfont);
@@ -89,63 +88,7 @@ pdfi_font0_map_glyph_to_unicode(gs_font *font, gs_glyph glyph, int ch, ushort *u
code = gs_error_undefined;
while (1) { /* Loop to make retrying with a substitute CID easier */
/* Favour the ToUnicode if one exists */
- if (tounicode) {
- int l = 0;
- gs_cmap_lookups_enum_t lenum;
- gs_cmap_lookups_enum_init((const gs_cmap_t *)tounicode->gscmap, 0, &lenum);
- while (l == 0 && (code = gs_cmap_enum_next_lookup(font->memory, &lenum)) == 0) {
- gs_cmap_lookups_enum_t counter = lenum;
- while (l == 0 && (code = gs_cmap_enum_next_entry(&counter) == 0)) {
- if (counter.entry.value_type == CODE_VALUE_CID) {
- unsigned int v = 0;
- for (i = 0; i < counter.entry.key_size; i++) {
- v |= (counter.entry.key[0][counter.entry.key_size - i - 1]) << (i * 8);
- }
- if (ch == v) {
- if (counter.entry.value.size == 1) {
- l = 2;
- if (unicode_return != NULL && length >= l) {
- unicode_return[0] = counter.entry.value.data[0];
- unicode_return[1] = counter.entry.value.data[1];
- }
- }
- else if (counter.entry.value.size == 2) {
- l = 2;
- if (unicode_return != NULL && length >= l) {
- unicode_return[0] = counter.entry.value.data[0];
- unicode_return[1] = counter.entry.value.data[1];
- }
- }
- else if (counter.entry.value.size == 3) {
- l = 4;
- if (unicode_return != NULL && length >= l) {
- unicode_return[0] = counter.entry.value.data[0];
- unicode_return[1] = counter.entry.value.data[1];
- unicode_return[2] = counter.entry.value.data[2];
- unicode_return[3] = 0;
- }
- }
- else {
- l = 4;
- if (unicode_return != NULL && length >= l) {
- unicode_return[0] = counter.entry.value.data[0];
- unicode_return[1] = counter.entry.value.data[1];
- unicode_return[2] = counter.entry.value.data[1];
- unicode_return[3] = counter.entry.value.data[3];
- }
- }
- }
- }
- else {
- l = 0;
- }
- }
- }
- if (l > 0)
- code = l;
- else
- code = gs_error_undefined;
- }
+ code = pdfi_tounicode_char_to_unicode(pt0font->ctx, (pdf_cmap *)pt0font->ToUnicode, glyph, ch, u, length);
if (code == gs_error_undefined && pt0font->decoding) {
const int *n;
@@ -310,17 +253,22 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
basefont = NULL;
}
- code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
- pdf_cmap *tu = NULL;
- code = pdfi_read_cmap(ctx, tounicode, &tu);
- pdfi_countdown(tounicode);
- tounicode = (pdf_obj *)tu;
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
+ if (code >= 0 && tounicode->type == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tounicode, &tu);
+ pdfi_countdown(tounicode);
+ tounicode = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
+ pdfi_countdown(tounicode);
+ tounicode = NULL;
+ code = 0;
+ }
}
- if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
- pdfi_countdown(tounicode);
+ else {
tounicode = NULL;
- code = 0;
}
if (descpfont == NULL) {
@@ -332,6 +280,11 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
descpfont = (pdf_font *)pf->client_data;
}
+ if (descpfont->pdfi_font_type < e_pdf_cidfont_type0 || descpfont->pdfi_font_type > e_pdf_cidfont_type4) {
+ code = gs_note_error(gs_error_invalidfont);
+ goto error;
+ }
+
if (descpfont != NULL && ((pdf_cidfont_t *)descpfont)->substitute) {
pdf_obj *csi = NULL;
pdf_string *reg = NULL, *ord = NULL;
@@ -342,7 +295,8 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
if (code >= 0) {
(void)pdfi_dict_get(ctx, (pdf_dict *)csi, "Registry", (pdf_obj **)&reg);
(void)pdfi_dict_get(ctx, (pdf_dict *)csi, "Ordering", (pdf_obj **)&ord);
- if (reg != NULL && ord != NULL) {
+ if (reg != NULL && reg->type == PDF_STRING
+ && ord != NULL && ord->type == PDF_STRING) {
r = (char *)reg->data;
rlen = reg->length;
o = (char *)ord->data;
@@ -404,6 +358,7 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
pdft0->indirect_gen = font_dict->indirect_gen;
pdft0->Encoding = (pdf_obj *)pcmap;
pdft0->ToUnicode = tounicode;
+ tounicode = NULL;
pdft0->DescendantFonts = arr;
pdft0->PDF_font = font_dict;
pdfi_countup(font_dict);
@@ -537,12 +492,7 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
/* object_num can be zero if the dictionary was defined inline */
if (pdft0->object_num != 0) {
- code = replace_cache_entry(ctx, (pdf_obj *)pdft0);
- if (code < 0) {
- gs_free_object(ctx->memory, pfont0, "pdfi_read_type0_font(pfont0)");
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
+ (void)replace_cache_entry(ctx, (pdf_obj *)pdft0);
}
*ppdffont = (pdf_font *)pdft0;
diff --git a/pdf/pdf_font0.h b/pdf/pdf_font0.h
index a8a76c60..f033fbf5 100644
--- a/pdf/pdf_font0.h
+++ b/pdf/pdf_font0.h
@@ -26,7 +26,7 @@
int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont);
int pdfi_free_font_type0(pdf_obj *font);
-int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, pdf_font **ppfont);
+int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, int findex, pdf_font **ppfont);
int pdfi_free_font_cidtype2(pdf_obj *font);
diff --git a/pdf/pdf_font1.c b/pdf/pdf_font1.c
index 6586d891..87ba858b 100644
--- a/pdf/pdf_font1.c
+++ b/pdf/pdf_font1.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
@@ -506,6 +506,7 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pdf_obj *mapname = NULL;
pdf_obj *tmp = NULL;
pdf_font_type1 *t1f = NULL;
+ pdf_obj *tounicode = NULL;
ps_font_interp_private fpriv = { 0 };
(void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
@@ -556,6 +557,9 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->object_num = font_dict->object_num;
t1f->generation_num = font_dict->generation_num;
+ t1f->indirect_num = font_dict->indirect_num;
+ t1f->indirect_gen = font_dict->indirect_gen;
+
t1f->PDF_font = font_dict;
pdfi_countup(font_dict);
t1f->BaseFont = basefont;
@@ -584,6 +588,26 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->descflags |= 4;
}
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
+ if (code >= 0 && tounicode->type == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tounicode, &tu);
+ pdfi_countdown(tounicode);
+ tounicode = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
+ pdfi_countdown(tounicode);
+ tounicode = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tounicode = NULL;
+ }
+ t1f->ToUnicode = tounicode;
+ tounicode = NULL;
+
code = pdfi_dict_knownget_type(ctx, font_dict, "FirstChar", PDF_INT, &tmp);
if (code == 1) {
t1f->FirstChar = ((pdf_num *) tmp)->value.i;
@@ -683,14 +707,6 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pdfi_countup(t1f->Encoding);
}
- code = pdfi_dict_knownget(ctx, font_dict, "ToUnicode", &tmp);
- if (code == 1) {
- t1f->ToUnicode = tmp;
- tmp = NULL;
- }
- else {
- t1f->ToUnicode = NULL;
- }
t1f->CharStrings = fpriv.u.t1.CharStrings;
pdfi_countup(t1f->CharStrings);
pdfi_patch_charstrings_dict(t1f->CharStrings);
@@ -719,9 +735,7 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
}
/* object_num can be zero if the dictionary was defined inline */
if (t1f->object_num != 0) {
- code = replace_cache_entry(ctx, (pdf_obj *) t1f);
- if (code < 0)
- goto error;
+ (void)replace_cache_entry(ctx, (pdf_obj *) t1f);
}
*ppdffont = (pdf_font *) t1f;
}
@@ -730,6 +744,7 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
error:
pdfi_countdown(fontdesc);
pdfi_countdown(basefont);
+ pdfi_countdown(tounicode);
pdfi_countdown(mapname);
pdfi_countdown(tmp);
pdfi_countdown(fpriv.u.t1.Encoding);
@@ -761,9 +776,6 @@ pdfi_free_font_type1(pdf_obj *font)
pdf_font_type1 *t1f = (pdf_font_type1 *) font;
int i;
- if (t1f->pfont->UID.xvalues != NULL) {
- gs_free_object(OBJ_MEMORY(font), t1f->pfont->UID.xvalues, "pdfi_free_font_type1(xuid)");
- }
gs_free_object(OBJ_MEMORY(font), t1f->pfont, "Free Type 1 gs_font");
pdfi_countdown(t1f->PDF_font);
diff --git a/pdf/pdf_font11.c b/pdf/pdf_font11.c
index ebe0cd21..09712f60 100644
--- a/pdf/pdf_font11.c
+++ b/pdf/pdf_font11.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -276,7 +276,7 @@ pdfi_alloc_cidtype2_font(pdf_context *ctx, pdf_cidfont_type2 **font, bool is_cid
return 0;
}
-int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, pdf_font **ppfont)
+int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, int findex, pdf_font **ppfont)
{
pdf_cidfont_type2 *font;
int code = 0;
@@ -306,6 +306,9 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
pdfi_countup(font_dict);
font->object_num = font_dict->object_num;
font->generation_num = font_dict->generation_num;
+ font->indirect_num = font_dict->indirect_num;
+ font->indirect_gen = font_dict->indirect_gen;
+
font->FontDescriptor = (pdf_dict *)fontdesc;
fontdesc = NULL;
@@ -382,6 +385,48 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
obj = NULL;
}
+ cid2 = (gs_font_cid2 *)font->pfont;
+
+ code = pdfi_dict_knownget_type(ctx, font_dict, "CIDSystemInfo", PDF_DICT, (pdf_obj **)&obj);
+ if (code <= 0) {
+ cid2->cidata.common.CIDSystemInfo.Registry.data = NULL;
+ cid2->cidata.common.CIDSystemInfo.Registry.size = 0;
+ cid2->cidata.common.CIDSystemInfo.Ordering.data = NULL;
+ cid2->cidata.common.CIDSystemInfo.Ordering.size = 0;
+ }
+ else {
+ pdf_num *suppl = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Registry", PDF_STRING, (pdf_obj **)&font->registry);
+ if (code <= 0) {
+ cid2->cidata.common.CIDSystemInfo.Registry.data = NULL;
+ cid2->cidata.common.CIDSystemInfo.Registry.size = 0;
+ }
+ else {
+ cid2->cidata.common.CIDSystemInfo.Registry.data = font->registry->data;
+ cid2->cidata.common.CIDSystemInfo.Registry.size = font->registry->length;
+ }
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Ordering", PDF_STRING, (pdf_obj **)&font->ordering);
+ if (code <= 0) {
+ cid2->cidata.common.CIDSystemInfo.Ordering.data = NULL;
+ cid2->cidata.common.CIDSystemInfo.Ordering.size = 0;
+ }
+ else {
+ cid2->cidata.common.CIDSystemInfo.Ordering.data = font->ordering->data;
+ cid2->cidata.common.CIDSystemInfo.Ordering.size = font->ordering->length;
+ }
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Supplement", PDF_INT, (pdf_obj **)&suppl);
+ if (code <= 0) {
+ cid2->cidata.common.CIDSystemInfo.Supplement = font->supplement = 0;
+ }
+ else {
+ cid2->cidata.common.CIDSystemInfo.Supplement = font->supplement = suppl->value.i;
+ }
+ pdfi_countdown(suppl);
+ }
+ pdfi_countdown(obj);
+ obj = NULL;
+
code = gs_type42_font_init((gs_font_type42 *)font->pfont, 0);
if (code < 0) {
goto error;
@@ -390,7 +435,6 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
font->pfont->procs.glyph_info = pdfi_cidtype2_glyph_info;
font->pfont->procs.enumerate_glyph = pdfi_cidtype2_enumerate_glyph;
- cid2 = (gs_font_cid2 *)font->pfont;
if (font->cidtogidmap.size > 0) {
gs_font_cid2 *cid2 = (gs_font_cid2 *)font->pfont;
if (cid2->data.numGlyphs > font->cidtogidmap.size >> 1)
@@ -425,9 +469,7 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
/* object_num can be zero if the dictionary was defined inline */
if (font->object_num != 0) {
- code = replace_cache_entry(ctx, (pdf_obj *)font);
- if (code < 0)
- goto error;
+ (void)replace_cache_entry(ctx, (pdf_obj *)font);
}
*ppfont = (pdf_font *)font;
@@ -454,6 +496,8 @@ int pdfi_free_font_cidtype2(pdf_obj *font)
pdfi_countdown(pdfcidf->W);
pdfi_countdown(pdfcidf->DW2);
pdfi_countdown(pdfcidf->W2);
+ pdfi_countdown(pdfcidf->registry);
+ pdfi_countdown(pdfcidf->ordering);
gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf, "pdfi_free_font_cidtype2(pdfcidf)");
return 0;
diff --git a/pdf/pdf_font1C.c b/pdf/pdf_font1C.c
index 10570912..f4788845 100644
--- a/pdf/pdf_font1C.c
+++ b/pdf/pdf_font1C.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
@@ -128,7 +128,7 @@ pdfi_cff_glyph_data(gs_font_type1 *pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
*/
if (cfffont->Encoding == NULL) {
char indstring[33];
- int l = gs_snprintf(indstring, 32, "%u", (unsigned int)glyph);
+ int l = gs_snprintf(indstring, sizeof(indstring), "%u", (unsigned int)glyph);
code = pdfi_name_alloc(ctx, (byte *) indstring, l, (pdf_obj **) &glyphname);
if (code >= 0)
@@ -431,18 +431,21 @@ pdfi_cff_cid_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_glyph_data_t *p
gid = pdffont9->cidtogidmap.data[gid << 1] << 8 | pdffont9->cidtogidmap.data[(gid << 1) + 1];
}
- l = snprintf(nbuf, 64, "%" PRId64, gid);
+ l = gs_snprintf(nbuf, sizeof(nbuf), "%" PRId64, gid);
code = pdfi_name_alloc(pdffont9->ctx, (byte *) nbuf, l, (pdf_obj **) &glyphname);
if (code >= 0) {
pdfi_countup(glyphname);
code = pdfi_dict_get_by_key(pdffont9->ctx, pdffont9->CharStrings, glyphname, (pdf_obj **) &charstring);
- if (code >= 0 && charstring->length > 1) {
- if (gscidfont->cidata.FDBytes == 0)
- *pfidx = 0;
- else
- *pfidx = (int)charstring->data[0];
- if (pgd)
+ if (code >= 0 && charstring->length >= gscidfont->cidata.FDBytes) {
+ if (gscidfont->cidata.FDBytes != 0) {
+ if ((int)charstring->data[0] > gscidfont->cidata.FDArray_size)
+ code = gs_note_error(gs_error_invalidfont);
+ else
+ *pfidx = (int)charstring->data[0];
+ }
+
+ if (code >= 0 && pgd && ((int64_t)charstring->length - (int64_t)gscidfont->cidata.FDBytes) >= 0)
gs_glyph_data_from_bytes(pgd, charstring->data + gscidfont->cidata.FDBytes, 0, charstring->length - gscidfont->cidata.FDBytes, NULL);
}
}
@@ -452,6 +455,7 @@ pdfi_cff_cid_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_glyph_data_t *p
return code;
}
+
static int
pdfi_cff_cidfont_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
int members, gs_glyph_info_t *info)
@@ -541,7 +545,6 @@ u32(const byte *p)
}
-
static int
subrbias(int count)
{
@@ -787,15 +790,17 @@ pdfi_read_cff_integer(byte *p, byte *e, int b0, int *val)
return p;
}
+#define PDFI_CFF_STACK_SIZE 48
+
static int
-pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_offsets *offsets)
+pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_offsets *offsets, bool topdict)
{
pdfi_cff_font_priv *font = &ptpriv->pdfcffpriv;
struct
{
int ival;
float fval;
- } args[48];
+ } args[PDFI_CFF_STACK_SIZE];
int offset;
int b0, n;
double f;
@@ -808,7 +813,7 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
offset = p - font->cffdata;
n = 0;
- while (p < e) {
+ while (p < e && code >= 0) {
b0 = *p++;
switch (b0) {
@@ -832,186 +837,288 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
}
b0 = 0x100 | *p++;
}
- if (b0 == 13) { /* UniqueID */
- }
-
- if (b0 == 14) { /* XUID */
- }
+ switch (b0) {
+ case 13: /* UniqueID */
+ break;
- if (b0 == 15) {
- offsets->charset_off = args[0].ival;
- }
+ case 14:
+ break; /* XUID */
- if (b0 == 16) {
- offsets->encoding_off = args[0].ival;
- }
+ /* some CFF file offsets */
+ case 15:
+ {
+ if (args[0].ival < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ break;
+ }
+ offsets->charset_off = args[0].ival;
+ break;
+ }
+ case 16:
+ {
+ if (args[0].ival < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ break;
+ }
+ offsets->encoding_off = args[0].ival;
+ break;
+ }
+ case 17:
+ {
+ if (args[0].ival < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ break;
+ }
+ font->charstrings = font->cffdata + args[0].ival;
+ break;
+ }
- /* some CFF file offsets */
+ case 18:
+ {
+ offsets->private_size = args[0].ival;
+ if (args[1].ival < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ break;
+ }
+ offsets->private_off = args[1].ival;
+ /* Catch a broken font with a self referencing Private dict */
+ if (topdict == true)
+ do_priv = offsets->private_size > 0 ? true : false;
+ else {
+ do_priv = false;
+ code = gs_error_invalidfont;
+ break;
+ }
+ break;
+ }
- if (b0 == 17) {
- font->charstrings = font->cffdata + args[0].ival;
- }
+ case 19:
+ {
+ if (args[0].ival < 0) {
+ code = gs_note_error(gs_error_invalidfont);
+ break;
+ }
+ font->subrs = font->cffdata + offset + args[0].ival;
+ break;
+ }
- if (b0 == 18) {
- offsets->private_size = args[0].ival;
- offsets->private_off = args[1].ival;
- do_priv = offsets->private_size > 0 ? true : false;
- }
+ case 256 | 30:
+ {
+ code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &font->registry, font, offsets, args[0].ival);
+ if (code < 0)
+ break;
+ code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &font->ordering, font, offsets, args[1].ival);
+ if (code < 0)
+ break;
+ font->supplement = args[2].ival;
+ offsets->have_ros = true;
+ ptpriv->FontType = ft_CID_encrypted;
+ break;
+ }
- if (b0 == 19) {
- font->subrs = font->cffdata + offset + args[0].ival;
- }
+ case 256 | 34:
+ {
+ font->cidcount = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 30)) {
- code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &font->registry, font, offsets, args[0].ival);
- if (code < 0)
- return code;
- code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &font->ordering, font, offsets, args[1].ival);
- if (code < 0)
- return code;
- font->supplement = args[2].ival;
- offsets->have_ros = true;
- ptpriv->FontType = ft_CID_encrypted;
- }
+ case 256 | 35:
+ {
+ font->uidbase = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 34)) {
- font->cidcount = args[0].ival;
- }
+ case 256 | 36:
+ {
+ offsets->fdarray_off = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 35)) {
- font->uidbase = args[0].ival;
- }
+ case 256 | 37:
+ {
+ offsets->fdselect_off = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 36)) {
- offsets->fdarray_off = args[0].ival;
- }
+ case 256 | 38:
+ {
+ pdf_string *fnamestr = NULL;
- if (b0 == (256 | 37)) {
- offsets->fdselect_off = args[0].ival;
- }
+ code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &fnamestr, font, offsets, args[0].ival);
+ if (code >= 0) {
+ memcpy(ptpriv->font_name.chars, fnamestr->data, fnamestr->length);
+ memcpy(ptpriv->key_name.chars, fnamestr->data, fnamestr->length);
+ ptpriv->font_name.size = ptpriv->key_name.size = fnamestr->length;
+ pdfi_countdown(fnamestr);
+ }
+ break;
+ }
- if (b0 == (256 | 38)) {
- pdf_string *fnamestr = NULL;
+ /* Type1 stuff that need to be set for the ptpriv struct */
- code = pdfi_make_string_from_sid(font->ctx, (pdf_obj **) &fnamestr, font, offsets, args[0].ival);
- if (code >= 0) {
- memcpy(ptpriv->font_name.chars, fnamestr->data, fnamestr->length);
- memcpy(ptpriv->key_name.chars, fnamestr->data, fnamestr->length);
- ptpriv->font_name.size = ptpriv->key_name.size = fnamestr->length;
- pdfi_countdown(fnamestr);
+ case 256 | 6:
+ {
+ if (args[0].ival == 1) {
+ ptpriv->type1data.interpret = gs_type1_interpret;
+ ptpriv->type1data.lenIV = -1; /* FIXME */
+ }
+ break;
}
- }
- /* Type1 stuff that need to be set for the ptpriv struct */
+ case 256 | 7:
+ {
+ ptpriv->FontMatrix.xx = args[0].fval;
+ ptpriv->FontMatrix.xy = args[1].fval;
+ ptpriv->FontMatrix.yx = args[2].fval;
+ ptpriv->FontMatrix.yy = args[3].fval;
+ ptpriv->FontMatrix.tx = args[4].fval;
+ ptpriv->FontMatrix.ty = args[5].fval;
+ offsets->have_matrix = true;
+ break;
+ }
+ case 5:
+ {
+ ptpriv->FontBBox.p.x = args[0].fval;
+ ptpriv->FontBBox.p.y = args[1].fval;
+ ptpriv->FontBBox.q.x = args[2].fval;
+ ptpriv->FontBBox.q.y = args[3].fval;
+ break;
+ }
- if (b0 == (256 | 6)) {
- if (args[0].ival == 1) {
- ptpriv->type1data.interpret = gs_type1_interpret;
- ptpriv->type1data.lenIV = -1; /* FIXME */
+ case 20:
+ {
+ ptpriv->type1data.defaultWidthX = float2fixed(args[0].fval);
+ break;
}
- }
- if (b0 == (256 | 7)) {
- ptpriv->FontMatrix.xx = args[0].fval;
- ptpriv->FontMatrix.xy = args[1].fval;
- ptpriv->FontMatrix.yx = args[2].fval;
- ptpriv->FontMatrix.yy = args[3].fval;
- ptpriv->FontMatrix.tx = args[4].fval;
- ptpriv->FontMatrix.ty = args[5].fval;
- offsets->have_matrix = true;
- }
+ case 21:
+ {
+ ptpriv->type1data.nominalWidthX = float2fixed(args[0].fval);
+ break;
+ }
- if (b0 == 5) {
- ptpriv->FontBBox.p.x = args[0].fval;
- ptpriv->FontBBox.p.y = args[1].fval;
- ptpriv->FontBBox.q.x = args[2].fval;
- ptpriv->FontBBox.q.y = args[3].fval;
- }
+ case 256 | 19:
+ {
+ ptpriv->type1data.initialRandomSeed = args[0].ival;
+ break;
+ }
- if (b0 == 20)
- ptpriv->type1data.defaultWidthX = float2fixed(args[0].fval);
+ case 6:
+ {
+ if (n > max_BlueValues * 2) n = max_BlueValues * 2;
+ ptpriv->type1data.BlueValues.count = n;
+ ptpriv->type1data.BlueValues.values[0] = args[0].fval;
+ for (i = 1; i < n; i++) {
+ ptpriv->type1data.BlueValues.values[i] = ptpriv->type1data.BlueValues.values[i - 1] + args[i].fval;
+ }
+ break;
+ }
- if (b0 == 21)
- ptpriv->type1data.nominalWidthX = float2fixed(args[0].fval);
+ case 7:
+ {
+ if (n > max_OtherBlues * 2) n = max_OtherBlues * 2;
+ ptpriv->type1data.OtherBlues.count = n;
+ ptpriv->type1data.OtherBlues.values[0] = args[0].fval;
+ for (i = 1; i < n; i++) {
+ ptpriv->type1data.OtherBlues.values[i] = ptpriv->type1data.OtherBlues.values[i - 1] + args[i].fval;
+ }
+ break;
+ }
- if (b0 == (256 | 19))
- ptpriv->type1data.initialRandomSeed = args[0].ival;
+ case 8:
+ {
+ if (n > max_FamilyBlues * 2) n = max_FamilyBlues * 2;
+ ptpriv->type1data.FamilyBlues.count = n;
+ ptpriv->type1data.FamilyBlues.values[0] = args[0].fval;
+ for (i = 1; i < n; i++) {
+ ptpriv->type1data.FamilyBlues.values[i] = ptpriv->type1data.FamilyBlues.values[i - 1] + args[i].fval;
+ }
+ break;
+ }
- if (b0 == 6) {
- ptpriv->type1data.BlueValues.count = n;
- ptpriv->type1data.BlueValues.values[0] = args[0].fval;
- for (i = 1; i < n; i++) {
- ptpriv->type1data.BlueValues.values[i] = ptpriv->type1data.BlueValues.values[i - 1] + args[i].fval;
+ case 9:
+ {
+ if (n > max_FamilyOtherBlues * 2) n = max_FamilyOtherBlues * 2;
+ ptpriv->type1data.FamilyOtherBlues.count = n;
+ ptpriv->type1data.FamilyOtherBlues.values[0] = args[0].fval;
+ for (i = 1; i < n; i++) {
+ ptpriv->type1data.FamilyOtherBlues.values[i] = ptpriv->type1data.FamilyOtherBlues.values[i - 1] + args[i].fval;
+ }
+ break;
}
- }
- if (b0 == 7) {
- ptpriv->type1data.OtherBlues.count = n;
- ptpriv->type1data.OtherBlues.values[0] = args[0].fval;
- for (i = 1; i < n; i++) {
- ptpriv->type1data.OtherBlues.values[i] = ptpriv->type1data.OtherBlues.values[i - 1] + args[i].fval;
+ case 10:
+ {
+ ptpriv->type1data.StdHW.count = 1;
+ ptpriv->type1data.StdHW.values[0] = args[0].fval;
+ break;
}
- }
- if (b0 == 8) {
- ptpriv->type1data.FamilyBlues.count = n;
- ptpriv->type1data.FamilyBlues.values[0] = args[0].fval;
- for (i = 1; i < n; i++) {
- ptpriv->type1data.FamilyBlues.values[i] = ptpriv->type1data.FamilyBlues.values[i - 1] + args[i].fval;
+ case 11:
+ {
+ ptpriv->type1data.StdVW.count = 1;
+ ptpriv->type1data.StdVW.values[0] = args[0].fval;
+ break;
}
- }
- if (b0 == 9) {
- ptpriv->type1data.FamilyOtherBlues.count = n;
- ptpriv->type1data.FamilyOtherBlues.values[0] = args[0].fval;
- for (i = 1; i < n; i++) {
- ptpriv->type1data.FamilyOtherBlues.values[i] = ptpriv->type1data.FamilyOtherBlues.values[i - 1] + args[i].fval;
+ case 256 | 9:
+ {
+ ptpriv->type1data.BlueScale = args[0].fval;
+ break;
}
- }
- if (b0 == 10) {
- ptpriv->type1data.StdHW.count = 1;
- ptpriv->type1data.StdHW.values[0] = args[0].fval;
- }
+ case 256 | 10:
+ {
+ ptpriv->type1data.BlueShift = args[0].fval;
+ break;
+ }
- if (b0 == 11) {
- ptpriv->type1data.StdVW.count = 1;
- ptpriv->type1data.StdVW.values[0] = args[0].fval;
- }
+ case 256 | 11:
+ {
+ ptpriv->type1data.BlueFuzz = (int)args[0].fval;
+ break;
+ }
- if (b0 == (256 | 9))
- ptpriv->type1data.BlueScale = args[0].fval;
+ case 256 | 12:
+ {
+ if (n > max_StemSnap) n = max_StemSnap;
+ ptpriv->type1data.StemSnapH.count = n;
+ for (f = 0, i = 0; i < n; f += args[i].fval, i++)
+ ptpriv->type1data.StemSnapH.values[i] = f;
+ break;
+ }
- if (b0 == (256 | 10))
- ptpriv->type1data.BlueShift = args[0].fval;
+ case 256 | 13:
+ {
+ if (n > max_StemSnap) n = max_StemSnap;
+ ptpriv->type1data.StemSnapV.count = n;
+ for (f = 0, i = 0; i < n; f += args[i].fval, i++)
+ ptpriv->type1data.StemSnapV.values[i] = f;
+ break;
+ }
- if (b0 == (256 | 11))
- ptpriv->type1data.BlueFuzz = (int)args[0].fval;
+ case 256 | 14:
+ {
+ ptpriv->type1data.ForceBold = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 12)) {
- ptpriv->type1data.StemSnapH.count = n;
- for (f = 0, i = 0; i < n; f += args[i].fval, i++)
- ptpriv->type1data.StemSnapH.values[i] = f;
- }
+ case 256 | 17:
+ {
+ ptpriv->type1data.LanguageGroup = args[0].ival;
+ break;
+ }
- if (b0 == (256 | 13)) {
- ptpriv->type1data.StemSnapV.count = n;
- for (f = 0, i = 0; i < n; f += args[i].fval, i++)
- ptpriv->type1data.StemSnapV.values[i] = f;
+ case 256 | 18:
+ {
+ ptpriv->type1data.ExpansionFactor = args[0].fval;
+ break;
+ }
+ default:
+ break;
}
-
- if (b0 == (256 | 14))
- ptpriv->type1data.ForceBold = args[0].ival;
-
- if (b0 == (256 | 17))
- ptpriv->type1data.LanguageGroup = args[0].ival;
-
- if (b0 == (256 | 18))
- ptpriv->type1data.ExpansionFactor = args[0].fval;
-
n = 0;
}
-
else {
if (b0 == 30) {
p = pdfi_read_cff_real(p, e, &args[n].fval);
@@ -1041,6 +1148,10 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
dmprintf1(ptpriv->memory, "CFF: corrupt dictionary operand (b0 = %d)", b0);
}
}
+ if (n >= PDFI_CFF_STACK_SIZE) {
+ code = gs_error_invalidfont;
+ break;
+ }
}
/* recurse for the private dictionary */
@@ -1053,7 +1164,7 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
if (p == NULL)
code = gs_error_invalidfont;
else
- code = pdfi_read_cff_dict(font->cffdata + offsets->private_off, dend, ptpriv, offsets);
+ code = pdfi_read_cff_dict(font->cffdata + offsets->private_off, dend, ptpriv, offsets, false);
if (code < 0)
dmprintf(ptpriv->memory, "CFF: cannot read private dictionary");
@@ -1101,6 +1212,11 @@ pdfi_count_cff_index(byte *p, byte *e, int *countp)
p += offsize;
p--; /* stupid offsets */
+ if (last < 0) {
+ gs_throw(-1, "corrupt index");
+ return 0;
+ }
+
if (p + last > e) {
gs_throw(-1, "not enough data for index data");
return 0;
@@ -1268,79 +1384,84 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
}
}
else {
- code = pdfi_object_alloc(ctx, PDF_ARRAY, 256, (pdf_obj **) &font->Encoding);
- if (code < 0)
- return code;
+ if (font->cffdata + offsets->encoding_off > font->cffend) {
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ else {
+ code = pdfi_object_alloc(ctx, PDF_ARRAY, 256, (pdf_obj **) &font->Encoding);
+ if (code < 0)
+ return code;
- code = pdfi_name_alloc(ctx, (byte *) ".notdef", 7, (pdf_obj **) &ndname);
- if (code < 0)
- return code;
+ code = pdfi_name_alloc(ctx, (byte *) ".notdef", 7, (pdf_obj **) &ndname);
+ if (code < 0)
+ return code;
- pdfi_countup(font->Encoding);
- pdfi_countup(ndname);
- code = 0;
- /* Prepopulate with notdefs */
- for (i = 0; i < 256 && code >= 0; i++) {
- code = pdfi_array_put(ctx, font->Encoding, (uint64_t) i, (pdf_obj *) ndname);
- }
+ pdfi_countup(font->Encoding);
+ pdfi_countup(ndname);
+ code = 0;
+ /* Prepopulate with notdefs */
+ for (i = 0; i < 256 && code >= 0; i++) {
+ code = pdfi_array_put(ctx, font->Encoding, (uint64_t) i, (pdf_obj *) ndname);
+ }
- if (code >= 0) {
- byte *p = font->cffdata + offsets->encoding_off;
+ if (code >= 0) {
+ byte *p = font->cffdata + offsets->encoding_off;
- enc_format = p[0];
+ enc_format = p[0];
- lp = pdfi_find_cff_index(font->charstrings, font->cffend, 0, &s, &e);
- if (lp == NULL) {
- code = gs_note_error(gs_error_rangecheck);
- goto done;
- }
- code = pdfi_object_alloc(ctx, PDF_STRING, e - s, (pdf_obj **) &pstr);
- if (code < 0)
- goto done;
- memcpy(pstr->data, s, e - s);
- pdfi_countup(pstr);
- code =
- pdfi_dict_put_obj(ctx, font->CharStrings, (pdf_obj *) ndname, (pdf_obj *) pstr);
- pdfi_countdown(pstr);
- if (code < 0) {
- goto done;
- }
- pdfi_countdown(ndname);
- ndname = NULL; /* just to avoid bad things! */
+ lp = pdfi_find_cff_index(font->charstrings, font->cffend, 0, &s, &e);
+ if (lp == NULL) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto done;
+ }
+ code = pdfi_object_alloc(ctx, PDF_STRING, e - s, (pdf_obj **) &pstr);
+ if (code < 0)
+ goto done;
+ memcpy(pstr->data, s, e - s);
+ pdfi_countup(pstr);
+ code =
+ pdfi_dict_put_obj(ctx, font->CharStrings, (pdf_obj *) ndname, (pdf_obj *) pstr, true);
+ pdfi_countdown(pstr);
+ if (code < 0) {
+ goto done;
+ }
+ pdfi_countdown(ndname);
+ ndname = NULL; /* just to avoid bad things! */
+
+ if ((enc_format &0x7f) == 0) {
+ unsigned int n_codes = p[1];
- if ((enc_format &0x7f) == 0) {
- unsigned int n_codes = p[1];
+ if (p + 2 + n_codes > font->cffend) {
+ return_error(gs_error_invalidfont);
+ }
+ gid2char[0] = 0;
+ for (i = 0; i < n_codes; i++) {
+ gid2char[i + 1] = p[2 + i];
+ }
+ memset(gid2char + n_codes + 1, 0, sizeof(gid2char) - n_codes - 1);
+ supp_enc_offset = 2 + n_codes;
+ }
+ else if ((enc_format &0x7f) == 1) {
+ unsigned int n_ranges = p[1];
+ unsigned int first, left, j, k = 1;
- if (p + 2 + n_codes > font->cffend) {
- return_error(gs_error_invalidfont);
+ if (p + 2 + 2 * n_ranges > font->cffend) {
+ return_error(gs_error_invalidfont);
+ }
+ gid2char[0] = 0;
+ for (i = 0; i < n_ranges; i++) {
+ first = p[2 + 2 * i];
+ left = p[3 + 2 * i];
+ for (j = 0; j <= left && k < 256; j++)
+ gid2char[k++] = first + j;
+ }
+ memset(gid2char + k, 0, sizeof(gid2char) - k);
+ supp_enc_offset = 2 * n_ranges + 2;
}
- gid2char[0] = 0;
- for (i = 0; i < n_codes; i++) {
- gid2char[i + 1] = p[2 + i];
+ else {
+ return_error(gs_error_rangecheck);
}
- memset(gid2char + n_codes + 1, 0, sizeof(gid2char) - n_codes - 1);
- supp_enc_offset = 2 + n_codes;
- }
- else if ((enc_format &0x7f) == 1) {
- unsigned int n_ranges = p[1];
- unsigned int first, left, j, k = 1;
-
- if (p + 2 + 2 * n_ranges > font->cffend) {
- return_error(gs_error_invalidfont);
- }
- gid2char[0] = 0;
- for (i = 0; i < n_ranges; i++) {
- first = p[2 + 2 * i];
- left = p[3 + 2 * i];
- for (j = 0; j <= left && k < 256; j++)
- gid2char[k++] = first + j;
- }
- memset(gid2char + k, 0, sizeof(gid2char) - k);
- supp_enc_offset = 2 * n_ranges + 2;
- }
- else {
- return_error(gs_error_rangecheck);
}
}
}
@@ -1361,7 +1482,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
pdfi_countup(pstr);
if (ptpriv->forcecid) {
char buf[40];
- int len = gs_sprintf(buf, "%d", 0);
+ int len = gs_snprintf(buf, sizeof(buf), "%d", 0);
code = pdfi_name_alloc(ctx, (byte *) buf, len, &gname);
if (code < 0) {
@@ -1378,7 +1499,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
}
pdfi_countup(gname);
}
- code = pdfi_dict_put_obj(ctx, font->CharStrings, gname, (pdf_obj *) pstr);
+ code = pdfi_dict_put_obj(ctx, font->CharStrings, gname, (pdf_obj *) pstr, true);
pdfi_countdown(pstr);
pdfi_countdown(gname);
if (code < 0)
@@ -1399,7 +1520,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
if (ptpriv->forcecid) {
char buf[40];
- int len = gs_sprintf(buf, "%d", gid);
+ int len = gs_snprintf(buf, sizeof(buf), "%d", gid);
code = pdfi_name_alloc(ctx, (byte *) buf, len, &gname);
if (code < 0) {
@@ -1415,7 +1536,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
}
if ((code = pdfi_make_name_from_sid(ctx, &gname, font, offsets, sid)) < 0) {
char buf[40];
- int len = gs_sprintf(buf, "sid-%d", sid);
+ int len = gs_snprintf(buf, sizeof(buf), "sid-%d", sid);
code = pdfi_name_alloc(ctx, (byte *) buf, len, &gname);
if (code < 0) {
@@ -1425,7 +1546,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
}
}
pdfi_countup(gname);
- code = pdfi_dict_put_obj(ctx, font->CharStrings, gname, (pdf_obj *) pstr);
+ code = pdfi_dict_put_obj(ctx, font->CharStrings, gname, (pdf_obj *) pstr, true);
pdfi_countdown(pstr);
if (code < 0) {
pdfi_countdown(gname);
@@ -1437,7 +1558,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
pdfi_countdown(gname);
}
- if (offsets->encoding_off > 1 && (enc_format &0x80)) {
+ if (offsets->encoding_off > 1 && (enc_format & 0x80)) {
unsigned int n_supp, charcode, sid;
byte *p = font->cffdata + offsets->encoding_off + supp_enc_offset;
pdf_obj *gname;
@@ -1450,7 +1571,7 @@ pdfi_cff_build_encoding(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv, cff_fon
if ((code = pdfi_make_name_from_sid(ctx, &gname, font, offsets, sid)) < 0) {
char buf[40];
- int len = gs_sprintf(buf, "sid-%d", sid);
+ int len = gs_snprintf(buf, sizeof(buf), "sid-%d", sid);
if (len > 0)
code = pdfi_name_alloc(ctx, (byte *) buf, len, &gname);
@@ -1534,6 +1655,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
/* String index */
pstore = p;
p = pdfi_find_cff_index(p, e, 0, &strp, &stre);
+
offsets.strings_off = pstore - font->cffdata;
p = pdfi_count_cff_index(pstore, e, &count);
@@ -1550,7 +1672,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
font->NumGlobalSubrs = 0;
}
/* Read the top and private dictionaries */
- code = pdfi_read_cff_dict(dictp, dicte, ptpriv, &offsets);
+ code = pdfi_read_cff_dict(dictp, dicte, ptpriv, &offsets, true);
if (code < 0)
return gs_rethrow(code, "cannot read top dictionary");
@@ -1576,6 +1698,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
font->GlobalSubrs->refcnt = 1;
for (i = 0; i < font->NumGlobalSubrs; i++) {
pdf_string *gsubrstr;
+ pdf_obj *nullobj = NULL;
p = pdfi_find_cff_index(font->gsubrs, font->cffend, i, &strp, &stre);
if (p) {
@@ -1591,6 +1714,17 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
}
}
}
+ else {
+ code = 0;
+ if (nullobj == NULL)
+ code = pdfi_object_alloc(ctx, PDF_NULL, 1, (pdf_obj **) &nullobj);
+ if (code >= 0)
+ code = pdfi_array_put(ctx, font->GlobalSubrs, (uint64_t) i, (pdf_obj *) nullobj);
+ if (code < 0) {
+ pdfi_countdown(font->GlobalSubrs);
+ font->GlobalSubrs = NULL;
+ }
+ }
}
}
}
@@ -1598,10 +1732,11 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
font->Subrs = NULL;
if (font->NumSubrs > 0) {
code = pdfi_object_alloc(ctx, PDF_ARRAY, font->NumSubrs, (pdf_obj **) &font->Subrs);
- if (code >= 0) {
+ if (code >= 0 && font->Subrs != NULL) {
font->Subrs->refcnt = 1;
for (i = 0; i < font->NumSubrs; i++) {
pdf_string *subrstr;
+ pdf_obj *nullobj = NULL;
p = pdfi_find_cff_index(font->subrs, font->cffend, i, &strp, &stre);
if (p) {
@@ -1615,6 +1750,19 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
}
}
}
+ else {
+ code = 0;
+ if (nullobj == NULL)
+ code = pdfi_object_alloc(ctx, PDF_NULL, 1, (pdf_obj **) &nullobj);
+ if (code >= 0)
+ code = pdfi_array_put(ctx, font->Subrs, (uint64_t) i, (pdf_obj *) nullobj);
+ if (code < 0) {
+ pdfi_countdown(font->Subrs);
+ font->Subrs = NULL;
+ font->NumSubrs = 0;
+ break;
+ }
+ }
}
}
}
@@ -1641,6 +1789,9 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
charset_proc = expert_subset_charset_proc;
break;
default:{
+ if (font->cffdata + offsets.charset_off >= font->cffend)
+ return_error(gs_error_rangecheck);
+
switch ((int)font->cffdata[offsets.charset_off]) {
case 0:
charset_proc = format0_charset_proc;
@@ -1663,7 +1814,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
int (*fdselect_proc)(const byte *p, const byte *pe, unsigned int i);
p = pdfi_count_cff_index(font->cffdata + offsets.fdarray_off, e, &fdarray_size);
- if (!p)
+ if (!p || fdarray_size < 1 || fdarray_size > 64) /* 64 is arbitrary, but seems a reasonable upper limit */
return gs_rethrow(-1, "cannot read charstrings index");
ptpriv->cidata.FDBytes = 1; /* Basically, always 1 just now */
@@ -1700,7 +1851,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
if (fddicte > font->cffend)
fddicte = font->cffend;
- code = pdfi_read_cff_dict(fddictp, fddicte, &fdptpriv, &offsets);
+ code = pdfi_read_cff_dict(fddictp, fddicte, &fdptpriv, &offsets, true);
if (code < 0) {
ptpriv->cidata.FDArray[i] = NULL;
code = gs_note_error(gs_error_invalidfont);
@@ -1782,6 +1933,9 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
}
}
else {
+ if (font->cffdata + offsets.fdselect_off > font->cffend)
+ return_error(gs_error_rangecheck);
+
switch ((int)font->cffdata[offsets.fdselect_off]) {
case 0:
fdselect_proc = format0_fdselect_proc;
@@ -2124,17 +2278,16 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
/* Vestigial magic number check - we can't check the third byte, as we have out of
spec fonts that have a head size > 4
*/
- if (fbuf[0] == 1 && fbuf[1] == 0) {
+ if (fbuf[0] == 1 && fbuf[1] == 0 && code >= 0) {
pdfi_gs_cff_font_priv cffpriv;
- if (code >= 0) {
- pdfi_init_cff_font_priv(ctx, &cffpriv, fbuf, fbuflen, false);
- cffpriv.forcecid = forcecid;
- code = pdfi_read_cff(ctx, &cffpriv);
- }
+ pdfi_init_cff_font_priv(ctx, &cffpriv, fbuf, fbuflen, false);
+ cffpriv.forcecid = forcecid;
+ code = pdfi_read_cff(ctx, &cffpriv);
+
if (code >= 0) {
if (cffpriv.FontType == ft_CID_encrypted) {
- pdf_obj *obj;
+ pdf_obj *obj = NULL;
pdf_cidfont_type0 *cffcid;
gs_font_cid0 *pfont;
@@ -2155,9 +2308,50 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
pfont->FAPI = NULL;
pfont->base = (gs_font *) cffcid->pfont;
- cffcid->registry = cffpriv.pdfcffpriv.registry;
- cffcid->ordering = cffpriv.pdfcffpriv.ordering;
- cffcid->supplement = cffpriv.pdfcffpriv.supplement;
+ code = pdfi_dict_knownget_type(ctx, font_dict, "CIDSystemInfo", PDF_DICT, (pdf_obj **)&obj);
+ if (code <= 0) {
+ cffcid->registry = cffpriv.pdfcffpriv.registry;
+ cffcid->ordering = cffpriv.pdfcffpriv.ordering;
+ cffcid->supplement = cffpriv.pdfcffpriv.supplement;
+ }
+ else {
+ pdf_num *suppl = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Registry", PDF_STRING, (pdf_obj **)&cffcid->registry);
+ if (code <= 0) {
+ cffcid->registry = cffpriv.pdfcffpriv.registry;
+ }
+ else {
+ pdfi_countdown(cffpriv.pdfcffpriv.registry);
+ cffpriv.pdfcffpriv.registry = NULL;
+ }
+
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Ordering", PDF_STRING, (pdf_obj **)&cffcid->ordering);
+ if (code <= 0) {
+ cffcid->ordering = cffpriv.pdfcffpriv.ordering;
+ }
+ else {
+ pdfi_countdown(cffpriv.pdfcffpriv.ordering);
+ cffpriv.pdfcffpriv.ordering = NULL;
+ }
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)obj, "Supplement", PDF_INT, (pdf_obj **)&suppl);
+ if (code <= 0 || suppl->type != PDF_INT) {
+ cffcid->supplement = cffpriv.pdfcffpriv.supplement;
+ }
+ else {
+ cffcid->supplement = suppl->value.i;
+ }
+ pdfi_countdown(suppl);
+ }
+ pdfi_countdown(obj);
+ obj = NULL;
+
+ pfont->cidata.common.CIDSystemInfo.Registry.data = cffcid->registry->data;
+ pfont->cidata.common.CIDSystemInfo.Registry.size = cffcid->registry->length;
+ pfont->cidata.common.CIDSystemInfo.Ordering.data = cffcid->ordering->data;
+ pfont->cidata.common.CIDSystemInfo.Ordering.size = cffcid->ordering->length;
+ pfont->cidata.common.CIDSystemInfo.Supplement = cffcid->supplement;
+
cffcid->FontDescriptor = (pdf_dict *) fontdesc;
fontdesc = NULL;
@@ -2167,19 +2361,13 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->cidtogidmap.data = NULL;
cffcid->cidtogidmap.size = 0;
- pfont->cidata.common.CIDSystemInfo.Registry.data = cffcid->registry->data;
- pfont->cidata.common.CIDSystemInfo.Registry.size = cffcid->registry->length;
- pfont->cidata.common.CIDSystemInfo.Ordering.data = cffcid->ordering->data;
- pfont->cidata.common.CIDSystemInfo.Ordering.size = cffcid->ordering->length;
- pfont->cidata.common.CIDSystemInfo.Supplement = cffcid->supplement;
pfont->client_data = cffcid;
cffcid->object_num = font_dict->object_num;
cffcid->generation_num = font_dict->generation_num;
cffcid->indirect_num = font_dict->indirect_num;
cffcid->indirect_gen = font_dict->indirect_gen;
- cffcid->PDF_font = font_dict;
- pdfi_countup(font_dict);
+
cffcid->CharStrings = cffpriv.pdfcffpriv.CharStrings;
cffpriv.pdfcffpriv.CharStrings = NULL;
@@ -2253,6 +2441,7 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, (gs_font_base *)cffcid->pfont);
if (code < 0)
uid_set_invalid(&cffcid->pfont->UID);
+
}
else if (forcecid) {
pdf_obj *obj;
@@ -2329,8 +2518,7 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
fdcfffont->object_num = 0;
fdcfffont->generation_num = 0;
- fdcfffont->PDF_font = font_dict;
- pdfi_countup(font_dict);
+
(void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
fdcfffont->BaseFont = basefont;
fdcfffont->Name = basefont;
@@ -2340,9 +2528,12 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffpriv.pdfcffpriv.Encoding = NULL;
fdcfffont->CharStrings = cffpriv.pdfcffpriv.CharStrings;
+ cffpriv.pdfcffpriv.CharStrings = NULL;
fdcfffont->Subrs = cffpriv.pdfcffpriv.Subrs;
+ cffpriv.pdfcffpriv.Subrs = NULL;
fdcfffont->NumSubrs = cffpriv.pdfcffpriv.NumSubrs;
fdcfffont->GlobalSubrs = cffpriv.pdfcffpriv.GlobalSubrs;
+ cffpriv.pdfcffpriv.GlobalSubrs = NULL;
fdcfffont->NumGlobalSubrs = cffpriv.pdfcffpriv.NumGlobalSubrs;
cffcid->CharStrings = fdcfffont->CharStrings;
@@ -2356,9 +2547,6 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->FontDescriptor = (pdf_dict *) fontdesc;
fontdesc = NULL;
- cffcid->PDF_font = font_dict;
- pdfi_countup(font_dict);
-
cffcid->registry = registry;
cffcid->ordering = ordering;
registry = ordering = NULL;
@@ -2389,11 +2577,9 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->generation_num = font_dict->generation_num;
cffcid->indirect_num = font_dict->indirect_num;
cffcid->indirect_gen = font_dict->indirect_gen;
+
cffcid->PDF_font = font_dict;
pdfi_countup(font_dict);
- cffcid->CharStrings = cffpriv.pdfcffpriv.CharStrings;
- cffcid->Subrs = cffpriv.pdfcffpriv.Subrs;
- cffcid->GlobalSubrs = cffpriv.pdfcffpriv.GlobalSubrs;
cffcid->cidtogidmap.data = NULL;
cffcid->cidtogidmap.size = 0;
@@ -2457,6 +2643,7 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
else {
pdf_font_cff *cfffont;
gs_font_type1 *pfont = NULL;
+ pdf_obj *tounicode = NULL;
code = pdfi_alloc_cff_font(ctx, &cfffont, font_dict->object_num, false);
pfont = (gs_font_type1 *) cfffont->pfont;
@@ -2472,8 +2659,9 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cfffont->object_num = font_dict->object_num;
cfffont->generation_num = font_dict->generation_num;
- cfffont->PDF_font = font_dict;
- pdfi_countup(font_dict);
+ cfffont->indirect_num = font_dict->indirect_num;
+ cfffont->indirect_gen = font_dict->indirect_gen;
+
(void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
cfffont->BaseFont = basefont;
cfffont->Name = basefont;
@@ -2604,18 +2792,28 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cfffont->Encoding = cffpriv.pdfcffpriv.Encoding;
cffpriv.pdfcffpriv.Encoding = NULL;
}
-
- code = pdfi_dict_knownget(ctx, font_dict, "ToUnicode", &tmp);
- if (code == 1) {
- cfffont->ToUnicode = tmp;
- tmp = NULL;
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
+ if (code >= 0 && tounicode->type == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tounicode, &tu);
+ pdfi_countdown(tounicode);
+ tounicode = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
+ pdfi_countdown(tounicode);
+ tounicode = NULL;
+ code = 0;
+ }
}
else {
- cfffont->ToUnicode = NULL;
+ tounicode = NULL;
}
+ cfffont->ToUnicode = tounicode;
+ tounicode = NULL;
}
}
- error:
+error:
if (code < 0) {
pdfi_countdown(cffpriv.pdfcffpriv.Subrs);
pdfi_countdown(cffpriv.pdfcffpriv.GlobalSubrs);
@@ -2632,24 +2830,20 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
gs_free_object(ctx->memory, cffpriv.cidata.FDArray, "pdfi_read_cff_font(gs_font FDArray, error)");
}
}
- if (code >= 0) {
+ else {
code = gs_definefont(ctx->font_dir, (gs_font *) ppdfont->pfont);
- if (code < 0) {
- goto error;
- }
- code = pdfi_fapi_passfont((pdf_font *) ppdfont, 0, NULL, NULL, NULL, 0);
- if (code < 0) {
- goto error;
- }
+ if (code >= 0)
+ code = pdfi_fapi_passfont((pdf_font *) ppdfont, 0, NULL, NULL, NULL, 0);
+
/* object_num can be zero if the dictionary was defined inline */
- if (ppdfont->object_num != 0) {
- code = replace_cache_entry(ctx, (pdf_obj *) ppdfont);
- if (code < 0)
- goto error;
+ if (code >= 0 && ppdfont->object_num != 0) {
+ (void)replace_cache_entry(ctx, (pdf_obj *) ppdfont);
+ }
+ if (code >= 0) {
+ *ppdffont = (pdf_font *) ppdfont;
+ ppdfont = NULL;
}
- *ppdffont = (pdf_font *) ppdfont;
- ppdfont = NULL;
}
}
gs_free_object(ctx->memory, pfbuf, "pdfi_read_cff_font(fbuf)");
diff --git a/pdf/pdf_font3.c b/pdf/pdf_font3.c
index 155d8be5..7ecd3bff 100644
--- a/pdf/pdf_font3.c
+++ b/pdf/pdf_font3.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
@@ -19,10 +19,10 @@
#include "pdf_stack.h"
#include "pdf_array.h"
#include "pdf_dict.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_font.h"
#include "pdf_font3.h"
-#include "pdf_font_types.h"
#include "pdf_deref.h"
#include "gscencs.h"
#include "gscedata.h" /* For the encoding arrays */
@@ -81,7 +81,7 @@ pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
OBJ_CTX(font)->text.BlockDepth = 0;
OBJ_CTX(font)->text.inside_CharProc = true;
- OBJ_CTX(font)->text.CharProc_is_d1 = false;
+ OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none;
{
/* It turns out that if a type 3 font uses a stroke to draw, and does not
@@ -110,9 +110,11 @@ pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
/* Use the utility routine above to copy the fill colour to the stroke colour */
pdfi_type3_copy_color(&OBJ_CTX(font)->pgs->color[0], &OBJ_CTX(font)->pgs->color[1]);
- pdfi_gsave(OBJ_CTX(font));
- pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc");
- pdfi_grestore(OBJ_CTX(font));
+ code = pdfi_gsave(OBJ_CTX(font));
+ if (code >= 0) {
+ code = pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc");
+ (void)pdfi_grestore(OBJ_CTX(font));
+ }
/* Use the utility routine above to copy the temporary copy to the stroke colour */
pdfi_type3_copy_color(&tmp_color, &OBJ_CTX(font)->pgs->color[1]);
@@ -120,7 +122,7 @@ pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
}
OBJ_CTX(font)->text.inside_CharProc = false;
- OBJ_CTX(font)->text.CharProc_is_d1 = false;
+ OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none;
OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth;
build_char_error:
@@ -220,6 +222,7 @@ int pdfi_free_font_type3(pdf_obj *font)
pdfi_countdown(t3font->FontDescriptor);
pdfi_countdown(t3font->CharProcs);
pdfi_countdown(t3font->Encoding);
+ pdfi_countdown(t3font->ToUnicode);
gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font");
return 0;
}
@@ -231,6 +234,7 @@ int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
pdf_font_type3 *font = NULL;
pdf_obj *obj = NULL;
double f;
+ pdf_obj *tounicode = NULL;
*ppdffont = NULL;
code = alloc_type3_font(ctx, &font);
@@ -238,6 +242,9 @@ int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
return code;
font->object_num = font_dict->object_num;
+ font->generation_num = font_dict->generation_num;
+ font->indirect_num = font_dict->indirect_num;
+ font->indirect_gen = font_dict->indirect_gen;
code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj);
if (code < 0)
@@ -315,6 +322,27 @@ int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
font->PDF_font = font_dict;
pdfi_countup(font_dict);
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
+ if (code >= 0 && tounicode->type == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tounicode, &tu);
+ pdfi_countdown(tounicode);
+ tounicode = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
+ pdfi_countdown(tounicode);
+ tounicode = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tounicode = NULL;
+ }
+
+ font->ToUnicode = tounicode;
+ tounicode = NULL;
+
code = replace_cache_entry(ctx, (pdf_obj *)font);
if (code < 0)
goto font3_error;
diff --git a/pdf/pdf_fontTT.c b/pdf/pdf_fontTT.c
index 44f3799e..aec3ee7b 100644
--- a/pdf/pdf_fontTT.c
+++ b/pdf/pdf_fontTT.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
@@ -61,7 +61,7 @@ static gs_glyph pdfi_ttf_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space
uint ID;
int code;
- if ((ttfont->descflags & 4) != 0) {
+ if ((ttfont->descflags & 4) != 0 || sp == GLYPH_SPACE_INDEX) {
int code = pdfi_fapi_check_cmap_for_GID(pfont, (uint)chr, &ID);
if (code < 0 || ID == 0)
code = pdfi_fapi_check_cmap_for_GID(pfont, (uint)(chr | 0xf0 << 8), &ID);
@@ -94,11 +94,8 @@ static uint pdfi_type42_get_glyph_index(gs_font_type42 *pfont, gs_glyph glyph)
uint cc = 0;
int i, code = 0;
- if (glyph >= GS_MIN_GLYPH_INDEX)
- glyph -= GS_MIN_GLYPH_INDEX;
-
- if ((ttfont->descflags & 4) != 0) {
- gind = (uint)glyph;
+ if ((ttfont->descflags & 4) != 0 || glyph >= GS_MIN_GLYPH_INDEX) {
+ gind = (uint)glyph < GS_MIN_GLYPH_INDEX ? glyph : glyph - GS_MIN_GLYPH_INDEX;
}
else {
pdf_context *ctx = (pdf_context *)ttfont->ctx;
@@ -247,7 +244,7 @@ static int pdfi_ttf_glyph_name(gs_font *pfont, gs_glyph glyph, gs_const_string *
if (code < 0) {
char buf[64];
int l;
- l = gs_sprintf(buf, "~gs~gName~%04x", (uint)glyph);
+ l = gs_snprintf(buf, sizeof(buf), "~gs~gName~%04x", (uint)glyph);
code = (*ctx->get_glyph_index)(pfont, (byte *)buf, l, &ID);
}
else {
@@ -356,7 +353,7 @@ static int pdfi_set_type42_data_procs(gs_font_type42 *pfont)
return 0;
}
-int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, pdf_font **ppdffont)
+int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, int findex, pdf_font **ppdffont)
{
pdf_font_truetype *font = NULL;
int code = 0, num_chars = 0, i;
@@ -367,6 +364,7 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
int64_t descflags;
bool encoding_known = false;
bool forced_symbolic = false;
+ pdf_obj *tounicode = NULL;
if (ppdffont == NULL)
return_error(gs_error_invalidaccess);
@@ -383,6 +381,10 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
code = gs_note_error(gs_error_invalidfont);
goto error;
}
+ font->object_num = font_dict->object_num;
+ font->generation_num = font_dict->generation_num;
+ font->indirect_num = font_dict->indirect_num;
+ font->indirect_gen = font_dict->indirect_gen;
font->FontDescriptor = (pdf_dict *)fontdesc;
fontdesc = NULL;
@@ -450,6 +452,26 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
pdfi_countdown(obj);
obj = NULL;
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
+ if (code >= 0 && tounicode->type == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tounicode, &tu);
+ pdfi_countdown(tounicode);
+ tounicode = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tounicode != NULL && tounicode->type != PDF_CMAP)) {
+ pdfi_countdown(tounicode);
+ tounicode = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tounicode = NULL;
+ }
+ font->ToUnicode = tounicode;
+ tounicode = NULL;
+
code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &descflags);
if (code < 0)
descflags = 0;
@@ -576,9 +598,7 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
/* object_num can be zero if the dictionary was defined inline */
if (font->object_num != 0) {
- code = replace_cache_entry(ctx, (pdf_obj *)font);
- if (code < 0)
- goto error;
+ (void)replace_cache_entry(ctx, (pdf_obj *)font);
}
*ppdffont = (pdf_font *)font;
@@ -615,6 +635,8 @@ int pdfi_free_font_truetype(pdf_obj *font)
pdfi_countdown(ttfont->FontDescriptor);
pdfi_countdown(ttfont->Encoding);
pdfi_countdown(ttfont->BaseFont);
+ pdfi_countdown(ttfont->PDF_font);
+ pdfi_countdown(ttfont->ToUnicode);
gs_free_object(OBJ_MEMORY(ttfont), ttfont, "Free TrueType font");
return 0;
diff --git a/pdf/pdf_fontTT.h b/pdf/pdf_fontTT.h
index 1ce4cf8b..90e4086e 100644
--- a/pdf/pdf_fontTT.h
+++ b/pdf/pdf_fontTT.h
@@ -18,7 +18,7 @@
#ifndef PDF_TRUETYPE_FONT
#define PDF_TRUETYPE_FONT
-int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, pdf_font **ppdffont);
+int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, int findex, pdf_font **ppdffont);
int pdfi_free_font_truetype(pdf_obj *font);
#endif
diff --git a/pdf/pdf_fontps.c b/pdf/pdf_fontps.c
index 7ee9d2f0..3ab399b9 100644
--- a/pdf/pdf_fontps.c
+++ b/pdf/pdf_fontps.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -178,7 +178,7 @@ pdfi_pscript_interpret(pdf_ps_ctx_t *cs, byte *pdfpsbuf, int64_t buflen)
*pdfpsbuf != char_CR)
pdfpsbuf++;
- if (*pdfpsbuf == char_EOL)
+ if (pdfpsbuf < buflim && *pdfpsbuf == char_EOL)
pdfpsbuf++;
}
break;
@@ -376,6 +376,29 @@ pdfi_pscript_interpret(pdf_ps_ctx_t *cs, byte *pdfpsbuf, int64_t buflen)
return code;
}
+static inline bool pdf_ps_name_cmp(pdf_ps_stack_object_t *obj, const char *namestr)
+{
+ byte *d = NULL;
+ int l1, l2;
+
+ if (namestr) {
+ l2 = strlen(namestr);
+ }
+
+ if (obj->type == PDF_PS_OBJ_NAME) {
+ d = obj->val.name;
+ l1 = obj->size;
+ }
+ else if (obj->type == PDF_PS_OBJ_STRING) {
+ d = obj->val.name;
+ l1 = obj->size;
+ }
+ if (d != NULL && namestr != NULL && l1 == l2) {
+ return memcmp(d, namestr, l1) == 0 ? true : false;
+ }
+ return false;
+}
+
static int
ps_font_def_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
{
@@ -387,464 +410,494 @@ ps_font_def_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
}
if (pdf_ps_obj_has_type(&s->cur[-1], PDF_PS_OBJ_NAME)) {
- if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("FontName"))) {
- int fnlen = 0;
- char *pname = NULL;
-
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_NAME)) {
- fnlen = s->cur[0].size > gs_font_name_max ? gs_font_name_max : s->cur[0].size;
- pname = (char *)s->cur[0].val.name;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_STRING)) {
- fnlen = s->cur[0].size > gs_font_name_max ? gs_font_name_max : s->cur[0].size;
- pname = (char *)s->cur[0].val.string;
- }
- if (pname) {
- memcpy(priv->gsu.gst1.key_name.chars, pname, fnlen);
- priv->gsu.gst1.key_name.chars[fnlen] = '\0';
- priv->gsu.gst1.key_name.size = fnlen;
-
- memcpy(priv->gsu.gst1.font_name.chars, pname, fnlen);
- priv->gsu.gst1.font_name.chars[fnlen] = '\0';
- priv->gsu.gst1.font_name.size = fnlen;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("PaintType"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.PaintType = s->cur[0].val.i;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("StrokeWidth"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.StrokeWidth = s->cur[0].val.f;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.StrokeWidth = (float)s->cur[0].val.i;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("WMode"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.WMode = s->cur[0].val.i;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("lenIV"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.lenIV = s->cur[0].val.i;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("UniqueID"))) {
- /* Ignore UniqueID if we already have a XUID */
- if (priv->gsu.gst1.UID.id >= 0) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- uid_set_UniqueID(&priv->gsu.gst1.UID, s->cur[0].val.i);
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("XUID"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, size = s->cur[0].size;
- long *xvals = (long *)gs_alloc_bytes(mem, size *sizeof(long), "ps_font_def_func(xuid vals)");
-
- if (xvals != NULL) {
- for (i = 0; i < size; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- xvals[i] = s->cur[0].val.arr[i].val.i;
- }
- else {
- gs_free_object(mem, xvals, "ps_font_def_func(xuid vals)");
- xvals = NULL;
- break;
- }
- }
- }
- if (xvals != NULL) {
- if (priv->gsu.gst1.UID.xvalues != NULL)
- gs_free_object(mem, priv->gsu.gst1.UID.xvalues, "ps_font_def_func(old xuid vals)");
- uid_set_XUID(&priv->gsu.gst1.UID, xvals, size);
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("FontBBox"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, j;
- double bbox[4] = { 0, 0, 1000, 1000 };
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_ARRAY)) { /* This is (probably) a Blend/FontBBox entry */
- code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blendfontbbox);
- if (code >= 0) {
- pdfi_countup(priv->u.t1.blendfontbbox);
- for (i = 0; i < s->cur[0].size; i++) {
- pdf_ps_stack_object_t *arr = &s->cur[0].val.arr[i];
- pdf_array *parr;
- pdf_num *n;
- if (pdf_ps_obj_has_type(arr, PDF_PS_OBJ_ARRAY)) {
- code = pdfi_array_alloc(s->pdfi_ctx, arr->size, &parr);
- if (code < 0)
- break;
- pdfi_countup(parr);
-
- for (j = 0; j < arr->size; j++) {
- if (pdf_ps_obj_has_type(&arr->val.arr[j], PDF_PS_OBJ_INTEGER)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = arr->val.arr[j].val.i;
- }
- else if (pdf_ps_obj_has_type(&arr->val.arr[j], PDF_PS_OBJ_FLOAT)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.d = arr->val.arr[j].val.f;
- }
- else {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = 0;
- }
- if (code < 0)
- break;
- pdfi_countup(n);
- code = pdfi_array_put(s->pdfi_ctx, parr, j, (pdf_obj *)n);
- pdfi_countdown(n);
- if (code < 0) break;
- }
- }
- if (code >= 0)
- code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blendfontbbox, i, (pdf_obj *)parr);
- pdfi_countdown(parr);
- }
- }
- }
- else if (s->cur[0].size >= 4) {
- for (i = 0; i < 4; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- bbox[i] = (double)s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- bbox[i] = (double)s->cur[0].val.arr[i].val.f;
- }
- }
- priv->gsu.gst1.FontBBox.p.x = bbox[0];
- priv->gsu.gst1.FontBBox.p.y = bbox[1];
- priv->gsu.gst1.FontBBox.q.x = bbox[2];
- priv->gsu.gst1.FontBBox.q.y = bbox[3];
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("FontType"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.FontType = s->cur[0].val.i;
- priv->u.t1.pdfi_font_type = s->cur[0].val.i == 1 ? e_pdf_font_type1 : e_pdf_cidfont_type0;
- }
- else {
- priv->gsu.gst1.FontType = 1;
- priv->u.t1.pdfi_font_type = e_pdf_font_type1;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("FontMatrix"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY) && s->cur[0].size >= 6) {
- int i;
- double fmat[6] = { 0.001, 0, 0, 0.001, 0, 0 };
- for (i = 0; i < 6; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- fmat[i] = (double)s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- fmat[i] = (double)s->cur[0].val.arr[i].val.f;
- }
- }
- priv->gsu.gst1.FontMatrix.xx = fmat[0];
- priv->gsu.gst1.FontMatrix.xy = fmat[1];
- priv->gsu.gst1.FontMatrix.yx = fmat[2];
- priv->gsu.gst1.FontMatrix.yy = fmat[3];
- priv->gsu.gst1.FontMatrix.tx = fmat[4];
- priv->gsu.gst1.FontMatrix.ty = fmat[5];
- priv->gsu.gst1.orig_FontMatrix = priv->gsu.gst1.FontMatrix;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("BlueValues"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, size = s->cur[0].size < 14 ? s->cur[0].size : 14;
-
- for (i = 0; i < size; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.BlueValues.values[i] =
- (float)s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.BlueValues.values[i] = s->cur[0].val.arr[i].val.f;
- }
- else {
- if (i == 0)
- priv->gsu.gst1.data.BlueValues.values[i] = 0;
- else
- priv->gsu.gst1.data.BlueValues.values[i] = priv->gsu.gst1.data.BlueValues.values[i - 1] + 1;
- }
- }
- priv->gsu.gst1.data.BlueValues.count = size;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("BlueScale"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.BlueScale = (float)s->cur[0].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.BlueScale = (float)s->cur[0].val.f;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("StdHW"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.StdHW.values[0] = (float)s->cur[0].val.arr[0].val.i;
- priv->gsu.gst1.data.StdHW.count = 1;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.StdHW.values[0] = s->cur[0].val.arr[0].val.f;
- priv->gsu.gst1.data.StdHW.count = 1;
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("StdVW"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.StdVW.values[0] = (float)s->cur[0].val.arr[0].val.i;
- priv->gsu.gst1.data.StdVW.count = 1;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.StdVW.values[0] = s->cur[0].val.arr[0].val.f;
- priv->gsu.gst1.data.StdVW.count = 1;
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("StemSnapH"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, size = s->cur[0].size > 12 ? 12 : s->cur[0].size;
-
- for (i = 0; i < size; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.StemSnapH.values[i] = (float)s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.StemSnapH.values[i] = s->cur[0].val.arr[i].val.f;
- }
- }
- priv->gsu.gst1.data.StemSnapH.count = size;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("StemSnapV"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, size = s->cur[0].size > 12 ? 12 : s->cur[0].size;
-
- for (i = 0; i < size; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.StemSnapV.values[i] = (float)s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.StemSnapV.values[i] = s->cur[0].val.arr[i].val.f;
- }
- }
- priv->gsu.gst1.data.StemSnapH.count = size;
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("Encoding"))) {
- pdf_array *new_enc = NULL;
-
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_NAME)) {
- pdf_name *pname;
-
- code = pdfi_name_alloc(s->pdfi_ctx, (byte *) s->cur[0].val.name, s->cur[0].size, (pdf_obj **) &pname);
- if (code >= 0) {
- pdfi_countup(pname);
-
- code = pdfi_create_Encoding(s->pdfi_ctx, (pdf_obj *) pname, NULL, (pdf_obj **) &new_enc);
- if (code >= 0) {
- pdfi_countdown(priv->u.t1.Encoding);
- priv->u.t1.Encoding = new_enc;
- }
- pdfi_countdown(pname);
- }
- }
- else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i;
-
- code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &new_enc);
- if (code >= 0) {
- pdfi_countup(new_enc);
- for (i = 0; i < s->cur[0].size; i++) {
- pdf_name *n = NULL;
- byte *nm = (byte *) s->cur[0].val.arr[i].val.name;
- int nlen = s->cur[0].val.arr[i].size;
-
- code = pdfi_name_alloc(s->pdfi_ctx, (byte *) nm, nlen, (pdf_obj **) &n);
- if (code < 0)
- break;
- pdfi_countup(n);
- code = pdfi_array_put(s->pdfi_ctx, new_enc, (uint64_t) i, (pdf_obj *) n);
- pdfi_countdown(n);
- if (code < 0)
- break;
- }
- if (code < 0) {
- pdfi_countdown(new_enc);
- }
- else {
- pdfi_countdown(priv->u.t1.Encoding);
- priv->u.t1.Encoding = new_enc;
- new_enc = NULL;
- }
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("BlendDesignPositions"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blenddesignpositions);
- if (code >= 0) {
- int i, j;
- pdfi_countup(priv->u.t1.blenddesignpositions);
-
- for (i = 0; i < s->cur[0].size && code >= 0; i++) {
- pdf_ps_stack_object_t *so = &s->cur[0].val.arr[i];
-
- if (pdf_ps_obj_has_type(so, PDF_PS_OBJ_ARRAY)) {
- pdf_array *sa;
- code = pdfi_array_alloc(s->pdfi_ctx, so->size, &sa);
- if (code >= 0) {
- pdfi_countup(sa);
- for (j = 0; j < so->size; j++) {
- pdf_num *n;
- if (pdf_ps_obj_has_type(&so->val.arr[j], PDF_PS_OBJ_INTEGER)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = so->val.arr[j].val.i;
- }
- else if (pdf_ps_obj_has_type(&so->val.arr[j], PDF_PS_OBJ_FLOAT)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.d = so->val.arr[j].val.f;
- }
- else {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = 0;
- }
- if (code < 0)
- break;
- pdfi_countup(n);
- code = pdfi_array_put(s->pdfi_ctx, sa, j, (pdf_obj *)n);
- pdfi_countdown(n);
- if (code < 0) break;
- }
- }
- if (code >= 0) {
- pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignpositions, i, (pdf_obj *)sa);
- }
- pdfi_countdown(sa);
- }
- }
- }
-
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("BlendAxisTypes"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i;
- code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blendaxistypes);
- if (code >= 0) {
- pdfi_countup(priv->u.t1.blendaxistypes);
- for (i = 0; i < s->cur[0].size; i++) {
- pdf_ps_stack_object_t *so = &s->cur[0].val.arr[i];
- pdf_name *n;
- if (pdf_ps_obj_has_type(so, PDF_PS_OBJ_NAME)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_NAME, so->size, (pdf_obj **)&n);
- if (code >= 0) {
- pdfi_countup(n);
- memcpy(n->data, so->val.name, so->size);
- n->length = so->size;
- code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blendaxistypes, i, (pdf_obj *)n);
- pdfi_countdown(n);
- }
- }
- if (code < 0)
- break;
- }
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("BlendDesignMap"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i, j, k;
- pdf_ps_stack_object_t *arr1 = &s->cur[0], *arr2, *arr3;
- pdf_array *parr2, *parr3;
- code = pdfi_array_alloc(s->pdfi_ctx, arr1->size, &priv->u.t1.blenddesignmap);
- if (code >= 0) {
- pdfi_countup(priv->u.t1.blenddesignmap);
- for (i = 0; i < arr1->size && code >= 0; i++) {
- if (pdf_ps_obj_has_type(&arr1->val.arr[i], PDF_PS_OBJ_ARRAY)) {
- arr2 = &arr1->val.arr[i];
- code = pdfi_array_alloc(s->pdfi_ctx, arr2->size, &parr2);
- if (code < 0)
- break;
- for (j = 0; j < arr2->size; j++) {
- pdf_num *n;
-
- arr3 = &arr2->val.arr[j];
- code = pdfi_array_alloc(s->pdfi_ctx, arr3->size, &parr3);
- if (code < 0)
- break;
-
- for (k = 0; k < arr3->size; k++) {
- if (pdf_ps_obj_has_type(&arr3->val.arr[k], PDF_PS_OBJ_INTEGER)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = arr3->val.arr[k].val.i;
- }
- else if (pdf_ps_obj_has_type(&arr1->val.arr[i], PDF_PS_OBJ_FLOAT)) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.d = arr3->val.arr[k].val.f;
- }
- else {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
- if (code >= 0)
- n->value.i = 0;
- }
- if (code < 0)
- break;
- pdfi_countup(n);
- code = pdfi_array_put(s->pdfi_ctx, parr3, k, (pdf_obj *)n);
- pdfi_countdown(n);
- if (code < 0)
- break;
- }
- if (code < 0)
- break;
- pdfi_countup(parr3);
- code = pdfi_array_put(s->pdfi_ctx, parr2, j, (pdf_obj *)parr3);
- pdfi_countdown(parr3);
- }
- if (code < 0)
- break;
- pdfi_countup(parr2);
- code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignmap, i, (pdf_obj *)parr2);
- pdfi_countdown(parr2);
- }
- }
- }
- }
- }
- else if (!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("WeightVector"))) {
- if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
- int i;
- for (i = 0; i < s->cur[0].size; i++) {
- if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
- priv->gsu.gst1.data.WeightVector.values[i] = s->cur[0].val.arr[i].val.i;
- }
- else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
- priv->gsu.gst1.data.WeightVector.values[i] = s->cur[0].val.arr[i].val.f;
- }
- else {
- priv->gsu.gst1.data.WeightVector.values[i] = 0;
- }
- }
- priv->gsu.gst1.data.WeightVector.count = s->cur[0].size;
- }
+ switch (s->cur[-1].size) {
+
+ case 4:
+ if (pdf_ps_name_cmp(&s->cur[-1], "XUID")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, size = s->cur[0].size;
+ long *xvals = (long *)gs_alloc_bytes(mem, size *sizeof(long), "ps_font_def_func(xuid vals)");
+
+ if (xvals != NULL) {
+ for (i = 0; i < size; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ xvals[i] = s->cur[0].val.arr[i].val.i;
+ }
+ else {
+ gs_free_object(mem, xvals, "ps_font_def_func(xuid vals)");
+ xvals = NULL;
+ break;
+ }
+ }
+ }
+ if (xvals != NULL) {
+ if (priv->gsu.gst1.UID.xvalues != NULL)
+ gs_free_object(mem, priv->gsu.gst1.UID.xvalues, "ps_font_def_func(old xuid vals)");
+ uid_set_XUID(&priv->gsu.gst1.UID, xvals, size);
+ }
+ }
+ }
+ break;
+
+ case 5:
+ if (pdf_ps_name_cmp(&s->cur[-1], "StdHW")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY) && s->cur[0].size > 0) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.StdHW.values[0] = (float)s->cur[0].val.arr[0].val.i;
+ priv->gsu.gst1.data.StdHW.count = 1;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.StdHW.values[0] = s->cur[0].val.arr[0].val.f;
+ priv->gsu.gst1.data.StdHW.count = 1;
+ }
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "StdVW")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY) && s->cur[0].size > 0) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.StdVW.values[0] = (float)s->cur[0].val.arr[0].val.i;
+ priv->gsu.gst1.data.StdVW.count = 1;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.StdVW.values[0] = s->cur[0].val.arr[0].val.f;
+ priv->gsu.gst1.data.StdVW.count = 1;
+ }
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "WMode")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.WMode = s->cur[0].val.i;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "lenIV")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.lenIV = s->cur[0].val.i;
+ }
+ }
+ break;
+
+ case 8:
+ if (pdf_ps_name_cmp(&s->cur[-1], "FontName")) {
+ int fnlen = 0;
+ char *pname = NULL;
+
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_NAME)) {
+ fnlen = s->cur[0].size > gs_font_name_max ? gs_font_name_max : s->cur[0].size;
+ pname = (char *)s->cur[0].val.name;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_STRING)) {
+ fnlen = s->cur[0].size > gs_font_name_max ? gs_font_name_max : s->cur[0].size;
+ pname = (char *)s->cur[0].val.string;
+ }
+ if (pname) {
+ memcpy(priv->gsu.gst1.key_name.chars, pname, fnlen);
+ priv->gsu.gst1.key_name.chars[fnlen] = '\0';
+ priv->gsu.gst1.key_name.size = fnlen;
+
+ memcpy(priv->gsu.gst1.font_name.chars, pname, fnlen);
+ priv->gsu.gst1.font_name.chars[fnlen] = '\0';
+ priv->gsu.gst1.font_name.size = fnlen;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "FontBBox")) {
+ if (s->cur[0].size > 0 && pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, j;
+ double bbox[4] = { 0, 0, 1000, 1000 };
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[0], PDF_PS_OBJ_ARRAY)) { /* This is (probably) a Blend/FontBBox entry */
+ code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blendfontbbox);
+ if (code >= 0) {
+ pdfi_countup(priv->u.t1.blendfontbbox);
+ for (i = 0; i < s->cur[0].size; i++) {
+ pdf_ps_stack_object_t *arr = &s->cur[0].val.arr[i];
+ pdf_array *parr = NULL;
+ pdf_num *n;
+ if (pdf_ps_obj_has_type(arr, PDF_PS_OBJ_ARRAY)) {
+ code = pdfi_array_alloc(s->pdfi_ctx, arr->size, &parr);
+ if (code < 0)
+ break;
+ pdfi_countup(parr);
+
+ for (j = 0; j < arr->size; j++) {
+ if (pdf_ps_obj_has_type(&arr->val.arr[j], PDF_PS_OBJ_INTEGER)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = arr->val.arr[j].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&arr->val.arr[j], PDF_PS_OBJ_FLOAT)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.d = arr->val.arr[j].val.f;
+ }
+ else {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = 0;
+ }
+ if (code < 0)
+ break;
+ pdfi_countup(n);
+ code = pdfi_array_put(s->pdfi_ctx, parr, j, (pdf_obj *)n);
+ pdfi_countdown(n);
+ if (code < 0) break;
+ }
+ }
+ if (code >= 0)
+ code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blendfontbbox, i, (pdf_obj *)parr);
+ pdfi_countdown(parr);
+ }
+ }
+ }
+ else if (s->cur[0].size >= 4) {
+ for (i = 0; i < 4; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ bbox[i] = (double)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ bbox[i] = (double)s->cur[0].val.arr[i].val.f;
+ }
+ }
+ priv->gsu.gst1.FontBBox.p.x = bbox[0];
+ priv->gsu.gst1.FontBBox.p.y = bbox[1];
+ priv->gsu.gst1.FontBBox.q.x = bbox[2];
+ priv->gsu.gst1.FontBBox.q.y = bbox[3];
+ }
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "FontType")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.FontType = s->cur[0].val.i;
+ priv->u.t1.pdfi_font_type = s->cur[0].val.i == 1 ? e_pdf_font_type1 : e_pdf_cidfont_type0;
+ }
+ else {
+ priv->gsu.gst1.FontType = 1;
+ priv->u.t1.pdfi_font_type = e_pdf_font_type1;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "Encoding")) {
+ pdf_array *new_enc = NULL;
+
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_NAME)) {
+ pdf_name *pname;
+
+ code = pdfi_name_alloc(s->pdfi_ctx, (byte *) s->cur[0].val.name, s->cur[0].size, (pdf_obj **) &pname);
+ if (code >= 0) {
+ pdfi_countup(pname);
+
+ code = pdfi_create_Encoding(s->pdfi_ctx, (pdf_obj *) pname, NULL, (pdf_obj **) &new_enc);
+ if (code >= 0) {
+ pdfi_countdown(priv->u.t1.Encoding);
+ priv->u.t1.Encoding = new_enc;
+ }
+ pdfi_countdown(pname);
+ }
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i;
+
+ code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &new_enc);
+ if (code >= 0) {
+ pdfi_countup(new_enc);
+ for (i = 0; i < s->cur[0].size; i++) {
+ pdf_name *n = NULL;
+ byte *nm = (byte *) s->cur[0].val.arr[i].val.name;
+ int nlen = s->cur[0].val.arr[i].size;
+
+ code = pdfi_name_alloc(s->pdfi_ctx, (byte *) nm, nlen, (pdf_obj **) &n);
+ if (code < 0)
+ break;
+ pdfi_countup(n);
+ code = pdfi_array_put(s->pdfi_ctx, new_enc, (uint64_t) i, (pdf_obj *) n);
+ pdfi_countdown(n);
+ if (code < 0)
+ break;
+ }
+ if (code < 0) {
+ pdfi_countdown(new_enc);
+ }
+ else {
+ pdfi_countdown(priv->u.t1.Encoding);
+ priv->u.t1.Encoding = new_enc;
+ new_enc = NULL;
+ }
+ }
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "UniqueID")) {
+ /* Ignore UniqueID if we already have a XUID */
+ if (priv->gsu.gst1.UID.id >= 0) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ uid_set_UniqueID(&priv->gsu.gst1.UID, s->cur[0].val.i);
+ }
+ }
+ }
+ break;
+
+ case 9:
+ if (pdf_ps_name_cmp(&s->cur[-1], "PaintType")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.PaintType = s->cur[0].val.i;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "StemSnapH")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, size = s->cur[0].size > 12 ? 12 : s->cur[0].size;
+
+ for (i = 0; i < size; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.StemSnapH.values[i] = (float)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.StemSnapH.values[i] = s->cur[0].val.arr[i].val.f;
+ }
+ }
+ priv->gsu.gst1.data.StemSnapH.count = size;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "StemSnapV")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, size = s->cur[0].size > 12 ? 12 : s->cur[0].size;
+
+ for (i = 0; i < size; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.StemSnapV.values[i] = (float)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.StemSnapV.values[i] = s->cur[0].val.arr[i].val.f;
+ }
+ }
+ priv->gsu.gst1.data.StemSnapH.count = size;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "BlueScale")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.BlueScale = (float)s->cur[0].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.BlueScale = (float)s->cur[0].val.f;
+ }
+ }
+ break;
+
+ case 10:
+ if (pdf_ps_name_cmp(&s->cur[-1], "FontMatrix")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY) && s->cur[0].size >= 6) {
+ int i;
+ double fmat[6] = { 0.001, 0, 0, 0.001, 0, 0 };
+ for (i = 0; i < 6; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ fmat[i] = (double)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ fmat[i] = (double)s->cur[0].val.arr[i].val.f;
+ }
+ }
+ priv->gsu.gst1.FontMatrix.xx = fmat[0];
+ priv->gsu.gst1.FontMatrix.xy = fmat[1];
+ priv->gsu.gst1.FontMatrix.yx = fmat[2];
+ priv->gsu.gst1.FontMatrix.yy = fmat[3];
+ priv->gsu.gst1.FontMatrix.tx = fmat[4];
+ priv->gsu.gst1.FontMatrix.ty = fmat[5];
+ priv->gsu.gst1.orig_FontMatrix = priv->gsu.gst1.FontMatrix;
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "BlueValues")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, size = s->cur[0].size < 14 ? s->cur[0].size : 14;
+
+ for (i = 0; i < size; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.BlueValues.values[i] =
+ (float)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.BlueValues.values[i] = s->cur[0].val.arr[i].val.f;
+ }
+ else {
+ if (i == 0)
+ priv->gsu.gst1.data.BlueValues.values[i] = 0;
+ else
+ priv->gsu.gst1.data.BlueValues.values[i] = priv->gsu.gst1.data.BlueValues.values[i - 1] + 1;
+ }
+ }
+ priv->gsu.gst1.data.BlueValues.count = size;
+ }
+ }
+ break;
+
+ case 11:
+ if (pdf_ps_name_cmp(&s->cur[-1], "StrokeWidth")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.StrokeWidth = s->cur[0].val.f;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.StrokeWidth = (float)s->cur[0].val.i;
+ }
+ }
+ break;
+ case 12:
+ if (pdf_ps_name_cmp(&s->cur[-1], "WeightVector")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i;
+ for (i = 0; i < s->cur[0].size; i++) {
+ if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_INTEGER)) {
+ priv->gsu.gst1.data.WeightVector.values[i] = (float)s->cur[0].val.arr[i].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&s->cur[0].val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ priv->gsu.gst1.data.WeightVector.values[i] = s->cur[0].val.arr[i].val.f;
+ }
+ else {
+ priv->gsu.gst1.data.WeightVector.values[i] = 0;
+ }
+ }
+ priv->gsu.gst1.data.WeightVector.count = s->cur[0].size;
+ }
+ }
+ break;
+ case 14:
+ if (pdf_ps_name_cmp(&s->cur[-1], "BlendAxisTypes")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i;
+ code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blendaxistypes);
+ if (code >= 0) {
+ pdfi_countup(priv->u.t1.blendaxistypes);
+ for (i = 0; i < s->cur[0].size; i++) {
+ pdf_ps_stack_object_t *so = &s->cur[0].val.arr[i];
+ pdf_name *n;
+ if (pdf_ps_obj_has_type(so, PDF_PS_OBJ_NAME)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_NAME, so->size, (pdf_obj **)&n);
+ if (code >= 0) {
+ pdfi_countup(n);
+ memcpy(n->data, so->val.name, so->size);
+ n->length = so->size;
+ code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blendaxistypes, i, (pdf_obj *)n);
+ pdfi_countdown(n);
+ }
+ }
+ if (code < 0)
+ break;
+ }
+ }
+ }
+ }
+ else if (pdf_ps_name_cmp(&s->cur[-1], "BlendDesignMap")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ int i, j, k;
+ pdf_ps_stack_object_t *arr1 = &s->cur[0], *arr2, *arr3;
+ pdf_array *parr2, *parr3;
+ code = pdfi_array_alloc(s->pdfi_ctx, arr1->size, &priv->u.t1.blenddesignmap);
+ if (code >= 0) {
+ pdfi_countup(priv->u.t1.blenddesignmap);
+ for (i = 0; i < arr1->size && code >= 0; i++) {
+ if (pdf_ps_obj_has_type(&arr1->val.arr[i], PDF_PS_OBJ_ARRAY)) {
+ arr2 = &arr1->val.arr[i];
+ code = pdfi_array_alloc(s->pdfi_ctx, arr2->size, &parr2);
+ if (code < 0)
+ break;
+ for (j = 0; j < arr2->size; j++) {
+ pdf_num *n;
+
+ arr3 = &arr2->val.arr[j];
+ code = pdfi_array_alloc(s->pdfi_ctx, arr3->size, &parr3);
+ if (code < 0)
+ break;
+
+ for (k = 0; k < arr3->size; k++) {
+ if (pdf_ps_obj_has_type(&arr3->val.arr[k], PDF_PS_OBJ_INTEGER)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = arr3->val.arr[k].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&arr1->val.arr[i], PDF_PS_OBJ_FLOAT)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.d = arr3->val.arr[k].val.f;
+ }
+ else {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = 0;
+ }
+ if (code < 0)
+ break;
+ pdfi_countup(n);
+ code = pdfi_array_put(s->pdfi_ctx, parr3, k, (pdf_obj *)n);
+ pdfi_countdown(n);
+ if (code < 0)
+ break;
+ }
+ if (code < 0)
+ break;
+ pdfi_countup(parr3);
+ code = pdfi_array_put(s->pdfi_ctx, parr2, j, (pdf_obj *)parr3);
+ pdfi_countdown(parr3);
+ }
+ if (code < 0)
+ break;
+ pdfi_countup(parr2);
+ code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignmap, i, (pdf_obj *)parr2);
+ pdfi_countdown(parr2);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case 20:
+ if (pdf_ps_name_cmp(&s->cur[-1], "BlendDesignPositions")) {
+ if (pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_ARRAY)) {
+ code = pdfi_array_alloc(s->pdfi_ctx, s->cur[0].size, &priv->u.t1.blenddesignpositions);
+ if (code >= 0) {
+ int i, j;
+ pdfi_countup(priv->u.t1.blenddesignpositions);
+
+ for (i = 0; i < s->cur[0].size && code >= 0; i++) {
+ pdf_ps_stack_object_t *so = &s->cur[0].val.arr[i];
+
+ if (pdf_ps_obj_has_type(so, PDF_PS_OBJ_ARRAY)) {
+ pdf_array *sa;
+ code = pdfi_array_alloc(s->pdfi_ctx, so->size, &sa);
+ if (code >= 0) {
+ pdfi_countup(sa);
+ for (j = 0; j < so->size; j++) {
+ pdf_num *n;
+ if (pdf_ps_obj_has_type(&so->val.arr[j], PDF_PS_OBJ_INTEGER)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = so->val.arr[j].val.i;
+ }
+ else if (pdf_ps_obj_has_type(&so->val.arr[j], PDF_PS_OBJ_FLOAT)) {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_REAL, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.d = so->val.arr[j].val.f;
+ }
+ else {
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_INT, 0, (pdf_obj **)&n);
+ if (code >= 0)
+ n->value.i = 0;
+ }
+ if (code < 0)
+ break;
+ pdfi_countup(n);
+ code = pdfi_array_put(s->pdfi_ctx, sa, j, (pdf_obj *)n);
+ pdfi_countdown(n);
+ if (code < 0) break;
+ }
+ }
+ if (code >= 0) {
+ pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignpositions, i, (pdf_obj *)sa);
+ }
+ pdfi_countdown(sa);
+ }
+ }
+ }
+
+ }
+ }
+ break;
+
+ default:
+ break;
}
}
@@ -956,6 +1009,10 @@ ps_font_eexec_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
stream *strm;
int c;
+ if (bufend <= buf) {
+ return_error(gs_error_invalidfont);
+ }
+
strm = push_eexec_filter(mem, buf, bufend);
while (1) {
c = sgetc(strm);
@@ -1121,7 +1178,6 @@ pdf_ps_RD_oper_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
pdf_ps_obj_has_type(&s->cur[-1], PDF_PS_OBJ_NAME)) {
pdf_string *str = NULL;
pdf_obj *key = NULL;
- bool key_known;
size = s->cur[0].val.i;
buf++;
@@ -1133,24 +1189,21 @@ pdf_ps_RD_oper_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
pdfi_countup(key);
if (buf + size < bufend) {
- code = pdfi_dict_known_by_key(s->pdfi_ctx, priv->u.t1.CharStrings, (pdf_name *)key, &key_known);
- if (code >=0 && key_known != true) {
- code = pdfi_object_alloc(s->pdfi_ctx, PDF_STRING, size, (pdf_obj **) &str);
- if (code < 0) {
- pdfi_countdown(key);
- (void)pdf_ps_stack_pop(s, 2);
- return code;
- }
- pdfi_countup(str);
- memcpy(str->data, buf, size);
-
- code = pdfi_dict_put_obj(s->pdfi_ctx, priv->u.t1.CharStrings, key, (pdf_obj *) str);
- if (code < 0) {
- pdfi_countdown(str);
- pdfi_countdown(key);
- (void)pdf_ps_stack_pop(s, 2);
- return code;
- }
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_STRING, size, (pdf_obj **) &str);
+ if (code < 0) {
+ pdfi_countdown(key);
+ (void)pdf_ps_stack_pop(s, 2);
+ return code;
+ }
+ pdfi_countup(str);
+ memcpy(str->data, buf, size);
+
+ code = pdfi_dict_put_obj(s->pdfi_ctx, priv->u.t1.CharStrings, key, (pdf_obj *) str, false);
+ if (code < 0) {
+ pdfi_countdown(str);
+ pdfi_countdown(key);
+ (void)pdf_ps_stack_pop(s, 2);
+ return code;
}
}
pdfi_countdown(str);
@@ -1177,7 +1230,7 @@ pdf_ps_put_oper_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
pdf_ps_obj_has_type(&s->cur[-2], PDF_PS_OBJ_ARRAY) &&
pdf_ps_obj_has_type(&s->cur[-1], PDF_PS_OBJ_INTEGER) &&
pdf_ps_obj_has_type(&s->cur[0], PDF_PS_OBJ_NAME)) {
- if (s->cur[-1].val.i < s->cur[-2].size) {
+ if (s->cur[-1].val.i >= 0 && s->cur[-1].val.i < s->cur[-2].size) {
pdf_ps_make_name(&s->cur[-2].val.arr[s->cur[-1].val.i], s->cur[0].val.name, s->cur[0].size);
}
}
diff --git a/pdf/pdf_fontps.h b/pdf/pdf_fontps.h
index 45810a28..835f0066 100644
--- a/pdf/pdf_fontps.h
+++ b/pdf/pdf_fontps.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -201,6 +201,9 @@ static inline int pdf_ps_stack_push(pdf_ps_ctx_t *s)
s->cur = s->stack + currsize - 1;
s->toplim = s->stack + newsize - PDF_PS_STACK_GROW_SIZE;
}
+ else {
+ return_error(gs_error_VMerror);
+ }
}
}
s->cur++;
diff --git a/pdf/pdf_func.c b/pdf/pdf_func.c
index 9b7d5bb7..9537152e 100644
--- a/pdf/pdf_func.c
+++ b/pdf/pdf_func.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -146,15 +146,15 @@ static int
pdfi_parse_type4_func_stream(pdf_context *ctx, pdf_c_stream *function_stream, int depth, byte *ops, unsigned int *size)
{
int code;
- byte c;
+ int c;
char TokenBuffer[17];
unsigned int Size, IsReal;
byte *clause = NULL;
byte *p = (ops ? ops + *size : NULL);
- do {
- code = pdfi_read_bytes(ctx, &c, 1, 1, function_stream);
- if (code < 0)
+ while (1) {
+ c = pdfi_read_byte(ctx, function_stream);
+ if (c < 0)
break;
switch(c) {
case 0x20:
@@ -202,32 +202,30 @@ pdfi_parse_type4_func_stream(pdf_context *ctx, pdf_c_stream *function_stream, in
IsReal = 1;
else
IsReal = 0;
- TokenBuffer[0] = c;
- do {
- code = pdfi_read_bytes(ctx, &c, 1, 1, function_stream);
- if (code < 0)
- return code;
- if (code == 0)
+ TokenBuffer[0] = (byte)c;
+ while (1) {
+ c = pdfi_read_byte(ctx, function_stream);
+ if (c < 0)
return_error(gs_error_syntaxerror);
if (c == '.'){
if (IsReal == 1)
- code = gs_error_syntaxerror;
+ return_error(gs_error_syntaxerror);
else {
- TokenBuffer[Size++] = c;
+ TokenBuffer[Size++] = (byte)c;
IsReal = 1;
}
} else {
if (c >= '0' && c <= '9') {
- TokenBuffer[Size++] = c;
+ TokenBuffer[Size++] = (byte)c;
} else
break;
}
if (Size > NUMBERTOKENSIZE)
return_error(gs_error_syntaxerror);
- } while (code >= 0);
+ }
TokenBuffer[Size] = 0x00;
- pdfi_unread(ctx, function_stream, &c, 1);
+ pdfi_unread_byte(ctx, function_stream, (byte)c);
if (IsReal == 1) {
*size += put_float(&p, atof(TokenBuffer));
} else {
@@ -239,21 +237,19 @@ pdfi_parse_type4_func_stream(pdf_context *ctx, pdf_c_stream *function_stream, in
/* parse an operator */
Size = 1;
- TokenBuffer[0] = c;
- do {
- code = pdfi_read_bytes(ctx, &c, 1, 1, function_stream);
- if (code < 0)
- return code;
- if (code == 0)
+ TokenBuffer[0] = (byte)c;
+ while (1) {
+ c = pdfi_read_byte(ctx, function_stream);
+ if (c < 0)
return_error(gs_error_syntaxerror);
if (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d || c == '{' || c == '}')
break;
- TokenBuffer[Size++] = c;
+ TokenBuffer[Size++] = (byte)c;
if (Size > OPTOKENSIZE)
return_error(gs_error_syntaxerror);
- } while(code >= 0);
+ }
TokenBuffer[Size] = 0x00;
- pdfi_unread(ctx, function_stream, &c, 1);
+ pdfi_unread_byte(ctx, function_stream, (byte)c);
for (i=0;i < NumOps;i++) {
Op = (op_struct_t *)&ops_table[i];
if (Op->length < Size)
@@ -278,9 +274,9 @@ pdfi_parse_type4_func_stream(pdf_context *ctx, pdf_c_stream *function_stream, in
}
break;
}
- } while (code >= 0);
+ }
- return code;
+ return 0;
}
static int
@@ -335,12 +331,13 @@ pdfi_build_function_4(pdf_context *ctx, gs_function_params_t * mnDR,
ops[size] = PtCr_return;
code = pdfi_close_memory_stream(ctx, data_source_buffer, function_stream);
- if (code < 0) {
- function_stream = NULL;
+ function_stream = NULL;
+ if (code < 0)
goto function_4_error;
- }
params.ops.data = (const byte *)ops;
+ /* ops will now be freed with the function params, NULL ops now to avoid double free on error */
+ ops = NULL;
params.ops.size = size + 1;
code = gs_function_PtCr_init(ppfn, &params, ctx->memory);
if (code < 0)
@@ -459,7 +456,7 @@ pdfi_build_function_0(pdf_context *ctx, gs_function_params_t * mnDR,
for (i=0;i<params.m;i++) {
inputs *= params.Size[i];
}
- samples = params.n * params.BitsPerSample;
+ samples = params.n * (uint64_t)params.BitsPerSample;
samples *= inputs;
samples = samples >> 3;
if (samples > Length) {
@@ -566,7 +563,18 @@ pdfi_build_function_3(pdf_context *ctx, gs_function_params_t * mnDR,
for (i = 0; i < params.k; ++i) {
pdf_obj * rsubfn = NULL;
- code = pdfi_array_get(ctx, (pdf_array *)Functions, (int64_t)i, &rsubfn);
+ /* This is basically hacky. The test file /tests_private/pdf/pdf_1.7_ATS/WWTW61EC_file.pdf
+ * has a number of shadings on page 2. Although there are numerous shadings, they each use one
+ * of four functions. However, these functions are themselves type 3 functions with 255
+ * sub-functions. Because our cache only has 200 entries (at this moment), this overfills
+ * the cache, ejecting all the cached objects (and then some). Which means that we throw
+ * out any previous shadings or functions, meaning that on every use we have to reread them. This is,
+ * obviously, slow. So in the hope that reuse of *sub_functions* is unlikely, we choose to
+ * read the subfunction without caching. This means the main shadings, and the functions,
+ * remain cached so we can reuse them saving an enormous amount of time. If we ever find a file
+ * which significantly reuses sub-functions we may need to revisit this.
+ */
+ code = pdfi_array_get_nocache(ctx, (pdf_array *)Functions, (int64_t)i, &rsubfn);
if (code < 0)
goto function_3_error;
diff --git a/pdf/pdf_gstate.c b/pdf/pdf_gstate.c
index 7544aa48..c1444b4b 100644
--- a/pdf/pdf_gstate.c
+++ b/pdf/pdf_gstate.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -17,6 +17,7 @@
#include "pdf_int.h"
#include "pdf_doc.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_stack.h"
#include "pdf_dict.h"
@@ -113,7 +114,9 @@ pdfi_gstate_copy_cb(void *to, const void *from)
*/
if (igs_to != NULL) {
pdfi_gstate_smask_free(igs_to);
+ pdfi_countdown(igs_to->current_font);
*(pdfi_int_gstate *) igs_to = *igs_from;
+ pdfi_countup(igs_to->current_font);
pdfi_gstate_smask_install(igs_to, igs_from->memory, igs_from->SMask, igs_from->GroupGState);
}
return 0;
@@ -127,6 +130,7 @@ pdfi_gstate_free_cb(void *old, gs_memory_t * mem, gs_gstate *pgs)
if (old == NULL)
return;
pdfi_gstate_smask_free(igs);
+ pdfi_countdown(igs->current_font);
/* We need to use the graphics state memory, in case we are running under Ghostscript. */
gs_free_object(pgs->memory, igs, "pdfi_gstate_free");
}
@@ -145,6 +149,8 @@ pdfi_gstate_set_client(pdf_context *ctx, gs_gstate *pgs)
/* We need to use the graphics state memory, in case we are running under Ghostscript. */
igs = pdfi_gstate_alloc_cb(pgs->memory);
+ if (igs == NULL)
+ return_error(gs_error_VMerror);
igs->ctx = ctx;
gs_gstate_set_client(pgs, igs, &pdfi_gstate_procs, true /* TODO: client_has_pattern_streams ? */);
return 0;
@@ -252,93 +258,38 @@ int pdfi_op_Q(pdf_context *ctx)
return code;
}
+/* We want pdfi_grestore() so we can track and warn of "too many Qs"
+ * in the interests of symmetry, we also have pdfi_gsave()
+ */
int pdfi_gsave(pdf_context *ctx)
{
- int code;
-
- code = gs_gsave(ctx->pgs);
-
- if(code < 0)
- return code;
- else {
- pdfi_countup_current_font(ctx);
- return 0;
- }
+ return gs_gsave(ctx->pgs);
}
int pdfi_grestore(pdf_context *ctx)
{
- int code;
- pdf_font *font = NULL, *font1 = NULL;
+ int code = 0;
/* Make sure we have encountered as many gsave operations in this
* stream as grestores. If not, log an error
*/
if (ctx->pgs->level > ctx->current_stream_save.gsave_level) {
- font = pdfi_get_current_pdf_font(ctx);
-
code = gs_grestore(ctx->pgs);
-
- font1 = pdfi_get_current_pdf_font(ctx);
- if (font != NULL && (font != font1 || ((pdf_obj *)font)->refcnt > 1)) {
- /* TODO: This countdown might have been causing memory corruption (dangling pointer)
- * but seems to be okay now. Maybe was fixed by other memory issue. 8-28-19
- * If you come upon this comment in the future and it all seems fine, feel free to
- * clean this up... (delete comment, remove the commented out warning message, etc)
- */
-#if REFCNT_DEBUG
- dbgmprintf2(ctx->memory, "pdfi_grestore() counting down font UID %ld, refcnt %d\n",
- font->UID, font->refcnt);
-#endif
- // dbgmprintf(ctx->memory, "WARNING pdfi_grestore() DISABLED pdfi_countdown (FIXME!)\n");
- pdfi_countdown(font);
- }
-
- return code;
} else {
/* We don't throw an error here, we just ignore it and continue */
pdfi_set_warning(ctx, 0, NULL, W_PDF_TOOMANYQ, "pdfi_grestore", (char *)"ignoring q");
}
- return 0;
+ return code;
}
-/* gs_setgstate is somewhat unpleasant from our point of view, because it replaces
- * the content of the graphics state, without going through our pdfi_gsave/pdfi_grestore
- * functionaltiy. In particular we replace the current font in the graphics state when
- * we call it, and this means we *don't* count down the PDF_font object reference count
- * which leads to an incorrect count and either memory leaks or early freeing.
- * This function *requires* that the calling function will do a pdfi_gsave *before*
- * calling pdfi_setgstate, and a pdfi_grestore *after* calling pdfi_gs_setgstate.
- * it correctly increments/decrements the font reference counts for that condition
- * and no other.
- */
int pdfi_gs_setgstate(gs_gstate * pgs, const gs_gstate * pfrom)
{
- pdf_font *font = NULL;
int code = 0;
- /* We are going to release a reference to the font from the graphics state
- * (if there is one) so count it down to keep things straight.
- */
- if (pgs->font) {
- font = (pdf_font *)pgs->font->client_data;
- if (font)
- pdfi_countdown(font);
- }
-
code = gs_setgstate(pgs, pfrom);
if (code < 0)
return code;
- /* The copied gstate may have contained a font, and we expect to do a
- * pdfi_grestore on exit from here, which will count down the font
- * so count it up now in preparation.
- */
- if (pgs->font) {
- font = (pdf_font *)pgs->font->client_data;
- if (font)
- pdfi_countup(font);
- }
return code;
}
@@ -924,6 +875,11 @@ static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page
pdfi_countdown(o);
goto exit;
}
+ if (pfn[i]->params.m != 1 || pfn[i]->params.n != 1) {
+ pdfi_countdown(o);
+ code = gs_note_error(gs_error_rangecheck);
+ goto exit;
+ }
} else {
pdfi_countdown(o);
code = gs_note_error(gs_error_typecheck);
@@ -987,7 +943,6 @@ static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page
}
}
exit:
-// (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
for (i = 0; i < 4; i++) {
pdfi_free_function(ctx, pfn[i]);
}
@@ -1006,6 +961,11 @@ static int pdfi_set_gray_transfer(pdf_context *ctx, pdf_obj *tr_obj, pdf_dict *p
if (code < 0)
return code;
+ if (pfn->params.m != 1 || pfn->params.n != 1) {
+ (void)pdfi_free_function(ctx, pfn);
+ return_error(gs_error_rangecheck);
+ }
+
gs_settransfer_remap(ctx->pgs, gs_mapped_transfer, false);
for (i = 0; i < transfer_map_size; i++) {
float v, f;
@@ -1206,6 +1166,7 @@ static int build_type1_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
gs_screen_enum *penum = NULL;
gs_point pt;
gx_transfer_map *pmap = NULL;
+ bool as;
code = pdfi_dict_get_number(ctx, halftone_dict, "Frequency", &f);
if (code < 0)
@@ -1219,6 +1180,12 @@ static int build_type1_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
if (code < 0)
return code;
+ code = pdfi_dict_get_bool(ctx, halftone_dict, "AccurateScreens", &as);
+ if (code == gs_error_undefined)
+ as = 0;
+ else if (code < 0)
+ return code;
+
order = (gx_ht_order *)gs_alloc_bytes(ctx->memory, sizeof(gx_ht_order), "build_type1_halftone");
if (order == NULL) {
code = gs_note_error(gs_error_VMerror);
@@ -1275,6 +1242,7 @@ static int build_type1_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
phtc->params.spot.transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
phtc->params.spot.transfer_closure.proc = 0;
phtc->params.spot.transfer_closure.data = 0;
+ phtc->params.spot.accurate_screens = as;
phtc->type = ht_type_spot;
code = pdfi_get_name_index(ctx, name, len, (unsigned int *)&phtc->cname);
if (code < 0)
@@ -2199,6 +2167,16 @@ static int GS_CA(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
if (code < 0)
return code;
+ if (d1 > 1.0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_CA_OUTOFRANGE, "GS_CA", NULL);
+ d1 = 1.0;
+ }
+
+ if (d1 < 0.0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_CA_OUTOFRANGE, "GS_CA", NULL);
+ d1 = 0.0;
+ }
+
code = gs_setstrokeconstantalpha(ctx->pgs, d1);
return code;
}
@@ -2212,6 +2190,16 @@ static int GS_ca(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
if (code < 0)
return code;
+ if (d1 > 1.0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_CA_OUTOFRANGE, "GS_ca", NULL);
+ d1 = 1.0;
+ }
+
+ if (d1 < 0.0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_CA_OUTOFRANGE, "GS_ca", NULL);
+ d1 = 0.0;
+ }
+
code = gs_setfillconstantalpha(ctx->pgs, d1);
return code;
}
diff --git a/pdf/pdf_gstate.h b/pdf/pdf_gstate.h
index 37bc55a9..2b314971 100644
--- a/pdf/pdf_gstate.h
+++ b/pdf/pdf_gstate.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -23,6 +23,7 @@ typedef struct int_gstate_s {
pdf_context *ctx;
pdf_dict *SMask; /* PDF only, null | dictionary | true */
gs_gstate *GroupGState; /* gstate associated with the SMask */
+ pdf_font *current_font; /* This is the pdfi font pointed at by the "client_data" pointer in the gs_font in the gs_gstate */
gs_memory_t *memory;
} pdfi_int_gstate;
diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c
index a52e5e8e..554cc344 100644
--- a/pdf/pdf_image.c
+++ b/pdf/pdf_image.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -17,6 +17,7 @@
#include "pdf_int.h"
#include "pdf_stack.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_doc.h"
#include "pdf_page.h"
@@ -470,6 +471,14 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
goto errorExit;
}
}
+ if (info->Height < 0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto errorExit;
+ }
+ info->Height = 0;
+ }
/* Required */
code = pdfi_dict_get_number2(ctx, image_dict, "Width", "W", &temp_f);
@@ -483,6 +492,14 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
goto errorExit;
}
}
+ if (info->Width < 0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto errorExit;
+ }
+ info->Width = 0;
+ }
/* Optional, default false */
code = pdfi_dict_get_bool2(ctx, image_dict, "ImageMask", "IM", &info->ImageMask);
@@ -699,13 +716,13 @@ pdfi_render_image(pdf_context *ctx, gs_pixel_image_t *pim, pdf_c_stream *image_s
{
int code;
gs_image_enum *penum = NULL;
- byte *buffer = NULL;
- uint64_t linelen, bytes_left;
+ uint64_t bytes_left;
uint64_t bytes_used = 0;
uint64_t bytes_avail = 0;
gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
int main_plane=0, mask_plane=0;
bool no_progress = false;
+ int min_left;
#if DEBUG_IMAGES
dbgmprintf(ctx->memory, "pdfi_render_image BEGIN\n");
@@ -715,8 +732,9 @@ pdfi_render_image(pdf_context *ctx, gs_pixel_image_t *pim, pdf_c_stream *image_s
if (code < 0)
return code;
- /* Disable overprint mode for images */
- gs_setoverprintmode(ctx->pgs, 0);
+ /* Disable overprint mode for images that are not a mask */
+ if (!ImageMask)
+ gs_setoverprintmode(ctx->pgs, 0);
penum = gs_image_enum_alloc(ctx->memory, "pdfi_render_image (gs_image_enum_alloc)");
if (!penum) {
@@ -761,37 +779,36 @@ pdfi_render_image(pdf_context *ctx, gs_pixel_image_t *pim, pdf_c_stream *image_s
main_plane = 0;
}
- /* Going to feed the data one line at a time.
- * This isn't required by gs_image_next_planes(), but it might make things simpler.
- */
- linelen = pdfi_get_image_line_size((gs_data_image_t *)pim, comps);
bytes_left = pdfi_get_image_data_size((gs_data_image_t *)pim, comps);
- buffer = gs_alloc_bytes(ctx->memory, linelen, "pdfi_render_image (buffer)");
- if (!buffer) {
- code = gs_note_error(gs_error_VMerror);
- goto cleanupExit;
- }
while (bytes_left > 0) {
uint used[GS_IMAGE_MAX_COMPONENTS];
- if (bytes_avail == 0) {
- code = pdfi_read_bytes(ctx, buffer, 1, linelen, image_stream);
- if (code < 0) {
- dmprintf3(ctx->memory,
- "WARNING: Image data error (pdfi_read_bytes) bytes_left=%ld, linelen=%ld, code=%d\n",
- bytes_left, linelen, code);
- goto cleanupExit;
- }
- if (code != linelen) {
- dmprintf3(ctx->memory, "WARNING: Image data mismatch, bytes_left=%ld, linelen=%ld, code=%d\n",
- bytes_left, linelen, code);
- code = gs_note_error(gs_error_limitcheck);
+ while ((bytes_avail = sbufavailable(image_stream->s)) <= (min_left = sbuf_min_left(image_stream->s))) {
+ switch (image_stream->s->end_status) {
+ case 0:
+ s_process_read_buf(image_stream->s);
+ continue;
+ case EOFC:
+ case INTC:
+ case CALLC:
+ break;
+ default:
+ /* case ERRC: */
+ code = gs_note_error(gs_error_ioerror);
goto cleanupExit;
}
+ break; /* for EOFC */
}
- plane_data[main_plane].data = buffer + bytes_used;
- plane_data[main_plane].size = linelen - bytes_used;
+ /*
+ * Note that in the EOF case, we can get here with no data
+ * available.
+ */
+ if (bytes_avail >= min_left)
+ bytes_avail = (bytes_avail - min_left); /* may be 0 */
+
+ plane_data[main_plane].data = sbufptr(image_stream->s);
+ plane_data[main_plane].size = bytes_avail;
code = gs_image_next_planes(penum, plane_data, used);
if (code < 0) {
@@ -810,6 +827,8 @@ pdfi_render_image(pdf_context *ctx, gs_pixel_image_t *pim, pdf_c_stream *image_s
no_progress = false;
}
+ (void)sbufskip(image_stream->s, used[main_plane]);
+
/* It might not always consume all the data, but so far the only case
* I have seen with that was one that had mask data.
* In that case, it used all of plane 0, and none of plane 1 on the first pass.
@@ -820,14 +839,12 @@ pdfi_render_image(pdf_context *ctx, gs_pixel_image_t *pim, pdf_c_stream *image_s
*/
bytes_used = used[main_plane];
bytes_left -= bytes_used;
- bytes_avail = linelen - bytes_used;
+ bytes_avail -= bytes_used;
}
code = 0;
cleanupExit:
- if (buffer)
- gs_free_object(ctx->memory, buffer, "pdfi_render_image (buffer)");
if (penum)
gs_image_cleanup_and_free_enum(penum, ctx->pgs);
pdfi_grestore(ctx);
@@ -876,7 +893,8 @@ pdfi_data_image_params(pdf_context *ctx, pdfi_image_info_t *info,
float minval, maxval;
/* TODO: Is there a less hacky way to identify Indexed case? */
- if (pcs && pcs->type == &gs_color_space_type_Indexed) {
+ if (pcs && (pcs->type == &gs_color_space_type_Indexed ||
+ pcs->type == &gs_color_space_type_Indexed_Named)) {
/* Default value is [0,N], where N=2^n-1, our hival (which depends on BPC)*/
minval = 0.0;
maxval = (float)((1 << info->BPC) - 1);
@@ -1230,7 +1248,7 @@ static int pdfi_create_JPX_Lab(pdf_context *ctx, pdf_obj **ColorSpace)
}
num = NULL;
- code = pdfi_dict_put_obj(ctx, Params, (pdf_obj *)WhitePointName, (pdf_obj *)WhitePoint);
+ code = pdfi_dict_put_obj(ctx, Params, (pdf_obj *)WhitePointName, (pdf_obj *)WhitePoint, true);
if (code < 0)
goto cleanupExit;
@@ -1268,7 +1286,7 @@ cleanupExit:
static int
pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *image_info,
- int *comps, gs_color_space **pcs)
+ int *comps, ulong dictkey, gs_color_space **pcs)
{
int code = 0;
pdfi_jpx_info_t *jpx_info = &image_info->jpx_info;
@@ -1276,11 +1294,33 @@ pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *
char *backup_color_name = NULL;
bool using_enum_cs = false;
- /* NOTE: Spec says ImageMask and ColorSpace mutually exclusive */
+ /* NOTE: Spec says ImageMask and ColorSpace mutually exclusive
+ * We need to make sure we do not have both set or we could end up treating
+ * an image as a mask or vice versa and trying to use a non-existent colour space.
+ */
if (image_info->ImageMask) {
- *comps = 1;
- *pcs = NULL;
- return 0;
+ if (image_info->ColorSpace == NULL) {
+ *comps = 1;
+ *pcs = NULL;
+ if (image_info->Mask) {
+ pdfi_countdown(image_info->Mask);
+ image_info->Mask = NULL;
+ }
+ return 0;
+ } else {
+ if (image_info->BPC != 1 || image_info->Mask != NULL) {
+ pdfi_set_error(ctx, 0, NULL, E_IMAGE_MASKWITHCOLOR, "pdfi_image_get_color", "BitsPerComonent is not 1, so treating as an image");
+ image_info->ImageMask = 0;
+ }
+ else {
+ pdfi_set_error(ctx, 0, NULL, E_IMAGE_MASKWITHCOLOR, "pdfi_image_get_color", "BitsPerComonent is 1, so treating as a mask");
+ pdfi_countdown(image_info->ColorSpace);
+ image_info->ColorSpace = NULL;
+ *comps = 1;
+ *pcs = NULL;
+ return 0;
+ }
+ }
}
ColorSpace = image_info->ColorSpace;
@@ -1303,7 +1343,7 @@ pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *
code = pdfi_create_icc_colorspace_from_stream(ctx, source, jpx_info->icc_offset,
jpx_info->icc_length, jpx_info->comps, &dummy,
- pcs);
+ dictkey, pcs);
if (code < 0) {
dmprintf2(ctx->memory,
"WARNING JPXDecode: Error setting icc colorspace (offset=%d,len=%d)\n",
@@ -1356,8 +1396,9 @@ pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *
{
char extra_info[gp_file_name_sizeof];
/* TODO: Could try DeviceRGB instead of erroring out? */
- gs_sprintf(extra_info, "**** Error: JPXDecode: Unsupported EnumCS %d\n", jpx_info->cs_enum);
+ gs_snprintf(extra_info, sizeof(extra_info), "**** Error: JPXDecode: Unsupported EnumCS %d\n", jpx_info->cs_enum);
pdfi_set_error(ctx, 0, NULL, E_PDF_IMAGECOLOR_ERROR, "pdfi_image_get_color", extra_info);
+ code = gs_note_error(gs_error_rangecheck);
goto cleanupExit;
}
}
@@ -1396,9 +1437,16 @@ pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *
if (ColorSpace->type == PDF_NAME) {
pdf_name *name = (pdf_name *)ColorSpace;
char str[100];
- memcpy(str, (const char *)name->data, name->length);
- str[name->length] = '\0';
- dmprintf1(ctx->memory, "NAME:%s\n", str);
+ int length = name->length;
+
+ if (length > 0) {
+ if (length > 99)
+ length = 99;
+
+ memcpy(str, (const char *)name->data, length);
+ str[length] = '\0';
+ dmprintf1(ctx->memory, "NAME:%s\n", str);
+ }
} else {
dmprintf(ctx->memory, "(not a name)\n");
}
@@ -1540,7 +1588,7 @@ static int
pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_stream *image_stream,
pdf_c_stream *source, bool inline_image)
{
- pdf_c_stream *new_stream = NULL;
+ pdf_c_stream *new_stream = NULL, *SFD_stream = NULL;
int code = 0, code1 = 0;
int comps = 0;
gs_color_space *pcs = NULL;
@@ -1558,12 +1606,15 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
uint64_t mask_size = 0;
pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
bool transparency_group = false;
+ bool op_blend_mode = false;
+ int blend_mode;
bool need_smask_cleanup = false;
bool maybe_jpxdecode = false;
pdfi_trans_state_t trans_state;
int saved_intent;
gs_offset_t stream_offset;
float save_strokeconstantalpha = 0.0f, save_fillconstantalpha = 0.0f;
+ int trans_required;
#if DEBUG_IMAGES
dbgmprintf(ctx->memory, "pdfi_do_image BEGIN\n");
@@ -1660,7 +1711,7 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
}
/* Get the color for this image */
- code = pdfi_image_get_color(ctx, source, &image_info, &comps, &pcs);
+ code = pdfi_image_get_color(ctx, source, &image_info, &comps, image_stream->object_num, &pcs);
if (code < 0)
goto cleanupExit;
@@ -1742,9 +1793,22 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
code = pdfi_gs_setcolorspace(ctx, pcs);
if (code < 0)
goto cleanupExit;
+
+ /* Try to set the device color again as that failure
+ is why we are here. If it fails again, something
+ is very wrong */
+ code = gx_set_dev_color(ctx->pgs);
+ if (code < 0)
+ goto cleanupExit;
}
}
}
+ else {
+ if (image_info.ImageMask == 0) {
+ code = gs_note_error(gs_error_undefined);
+ goto cleanupExit;
+ }
+ }
/* Make a fake SMask dict if needed for JPXDecode */
if (ctx->page.has_transparency && image_info.is_JPXDecode && image_info.SMaskInData != 0) {
@@ -1765,6 +1829,21 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
goto cleanupExit;
need_smask_cleanup = true;
}
+
+ /* If we are in an overprint situation this group will need
+ to have its blend mode set to compatible overprint. */
+ if (ctx->page.needs_OP) {
+ if (pdfi_trans_okOPcs(ctx)) {
+ if (gs_currentfilloverprint(ctx->pgs)) {
+ blend_mode = gs_currentblendmode(ctx->pgs);
+ code = gs_setblendmode(ctx->pgs, BLEND_MODE_CompatibleOverprint);
+ op_blend_mode = true;
+ if (code < 0)
+ goto cleanupExit;
+ }
+ }
+ }
+
if (has_Matte)
code = pdfi_trans_begin_isolated_group(ctx, true, pcs);
else
@@ -1887,8 +1966,15 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
}
/* Setup the data stream for the image data */
- if (!inline_image)
+ if (!inline_image) {
pdfi_seek(ctx, source, stream_offset, SEEK_SET);
+
+ code = pdfi_apply_SubFileDecode_filter(ctx, 0, "endstream", source, &SFD_stream, false);
+ if (code < 0)
+ goto cleanupExit;
+ source = SFD_stream;
+ }
+
code = pdfi_filter(ctx, image_stream, source, &new_stream, inline_image);
if (code < 0)
goto cleanupExit;
@@ -1936,7 +2022,18 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
code = pdfi_apply_imscale_filter(ctx, 0, image_info.Width, image_info.Height, s, &new_stream);
if (code < 0)
goto cleanupExit;
+ /* This adds the filter to the 'chain' of filter we created. When we close this filter
+ * it closes all the filters in the chain, back to either the SubFileDecode filter or the
+ * original main stream. If we don't patch this up then we leak memory for any filters
+ * applied in pdfi_filter above.
+ */
+ new_stream->original = s->original;
+ /* We'e created a new 'new_stream', which is a C stream, to hold the filter chain
+ * but we still need to free the original C stream 'wrapper' we created with pdfi_filter()
+ * Do that now.
+ */
+ gs_free_object(ctx->memory, s, "free stream replaced by adding image scaling filter");
image_info.Width *= 4;
image_info.Height *= 4;
pim->Width *= 4;
@@ -1947,9 +2044,13 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
}
}
- code = pdfi_image_setup_trans(ctx, &trans_state);
- if (code < 0)
- goto cleanupExit;
+ trans_required = pdfi_trans_required(ctx);
+
+ if (trans_required) {
+ code = pdfi_image_setup_trans(ctx, &trans_state);
+ if (code < 0)
+ goto cleanupExit;
+ }
/* Render the image */
code = pdfi_render_image(ctx, pim, new_stream,
@@ -1960,9 +2061,11 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
dmprintf1(ctx->memory, "WARNING: pdfi_do_image: error %d from pdfi_render_image\n", code);
}
- code1 = pdfi_trans_teardown(ctx, &trans_state);
- if (code == 0)
- code = code1;
+ if (trans_required) {
+ code1 = pdfi_trans_teardown(ctx, &trans_state);
+ if (code == 0)
+ code = code1;
+ }
cleanupExit:
if (code < 0)
@@ -1980,8 +2083,14 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
pdfi_trans_end_smask_notify(ctx);
}
+ if (op_blend_mode) {
+ code = gs_setblendmode(ctx->pgs, blend_mode);
+ }
+
if (new_stream)
pdfi_close_file(ctx, new_stream);
+ if (SFD_stream)
+ pdfi_close_file(ctx, SFD_stream);
if (mask_buffer)
gs_free_object(ctx->memory, mask_buffer, "pdfi_do_image (mask_buffer)");
@@ -2017,7 +2126,7 @@ int pdfi_ID(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_c_
* been decrypted, we don't need to decrypt any strings contained in the
* inline dictionary.
*/
- code = pdfi_dict_from_stack(ctx, 0, 0);
+ code = pdfi_dict_from_stack(ctx, 0, 0, false);
if (code < 0)
/* pdfi_dict_from_stack cleans up the stack so we don't need to in case of an error */
return code;
@@ -2200,6 +2309,8 @@ static int pdfi_form_stream_hack(pdf_context *ctx, pdf_dict *form_dict, pdf_stre
return 0;
if (!ctx->args.pdfstoponerror) {
+ pdf_obj *Parent = NULL;
+ pdf_dict *d = NULL;
pdf_dict *stream_dict = NULL;
code = pdfi_dict_knownget_type(ctx, form_dict, "Contents", PDF_STREAM,
@@ -2209,6 +2320,27 @@ static int pdfi_form_stream_hack(pdf_context *ctx, pdf_dict *form_dict, pdf_stre
code = gs_note_error(gs_error_typecheck);
goto exit;
}
+
+ d = form_dict;
+ pdfi_countup(d);
+ do {
+ code = pdfi_dict_knownget(ctx, d, "Parent", (pdf_obj **)&Parent);
+ if (code > 0) {
+ if (Parent->object_num == stream_obj->object_num) {
+ pdfi_countdown(d);
+ pdfi_countdown(Parent);
+ pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAMDICT, "pdfi_form_stream_hack", NULL);
+ code = gs_note_error(gs_error_undefined);
+ goto exit;
+ }
+ pdfi_countdown(d);
+ d = (pdf_dict *)Parent;
+ } else {
+ pdfi_countdown(d);
+ break;
+ }
+ } while (1);
+
code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
if (code < 0) {
pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAMDICT, "pdfi_form_stream_hack", NULL);
@@ -2402,7 +2534,7 @@ int pdfi_do_image_or_form(pdf_context *ctx, pdf_dict *stream_dict,
gs_offset_t savedoffset;
if (xobject_obj->type != PDF_STREAM) {
- gs_note_error(gs_error_typecheck);
+ code = gs_note_error(gs_error_typecheck);
goto exit;
}
savedoffset = pdfi_tell(ctx->main_stream);
@@ -2480,6 +2612,7 @@ int pdfi_Do(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
goto exit;
}
+ code = pdfi_loop_detector_cleartomark(ctx);
/* NOTE: Used to have a pdfi_gsave/pdfi_grestore around this, but it actually makes
* things render incorrectly (and isn't in the PS code).
* It also causes demo.ai.pdf to crash.
@@ -2494,14 +2627,12 @@ int pdfi_Do(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
// pdfi_gsave(ctx);
code = pdfi_do_image_or_form(ctx, stream_dict, page_dict, o);
// pdfi_grestore(ctx);
- if (code < 0)
- goto exit;
+ pdfi_countdown(o);
+ pdfi_pop(ctx, 1);
+ return code;
- exit:
- if (code < 0)
- (void)pdfi_loop_detector_cleartomark(ctx);
- else
- code = pdfi_loop_detector_cleartomark(ctx);
+exit:
+ (void)pdfi_loop_detector_cleartomark(ctx);
exit1:
/* No need to countdown 'n' because that points to the stack object, and we're going to pop that */
pdfi_countdown(o);
diff --git a/pdf/pdf_int.c b/pdf/pdf_int.c
index 555653b6..9493922b 100644
--- a/pdf/pdf_int.c
+++ b/pdf/pdf_int.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -25,7 +25,7 @@
#include "pdf_image.h"
#include "pdf_shading.h"
#include "pdf_font.h"
-#include "pdf_font.h"
+#include "pdf_font_types.h"
#include "pdf_cmap.h"
#include "pdf_text.h"
#include "pdf_gstate.h"
@@ -37,6 +37,8 @@
#include "pdf_optcontent.h"
#include "pdf_sec.h"
+#include "gsstate.h" /* for gs_gstate_free */
+
/* we use -ve returns for error, 0 for success and +ve for 'take an action' */
/* Defining tis return so we do not need to define a new error */
#define REPAIRED_KEYWORD 1
@@ -106,83 +108,114 @@ static int fromhex(char c)
*/
int pdfi_skip_white(pdf_context *ctx, pdf_c_stream *s)
{
- uint32_t read = 0;
- int32_t bytes = 0;
- byte c;
+ int c;
do {
- bytes = pdfi_read_bytes(ctx, &c, 1, 1, s);
- if (bytes < 0)
- return_error(gs_error_ioerror);
- if (bytes == 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return 0;
- read += bytes;
- } while (bytes != 0 && iswhite(c));
+ } while (iswhite(c));
- if (read > 0)
- pdfi_unread(ctx, s, &c, 1);
+ pdfi_unread_byte(ctx, s, (byte)c);
return 0;
}
int pdfi_skip_eol(pdf_context *ctx, pdf_c_stream *s)
{
- uint32_t read = 0;
- int32_t bytes = 0;
- byte c;
+ int c;
do {
- bytes = pdfi_read_bytes(ctx, &c, 1, 1, s);
- if (bytes == 0)
- return 0;
- if (read) {
- if (c == 0x0A)
- return 0;
- pdfi_unread(ctx, s, &c, 1);
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0 || c == 0x0a)
return 0;
- }
- if (c == 0x0D)
- read++;
- } while (c != 0x0A);
+ } while (c != 0x0d);
+ c = pdfi_read_byte(ctx, s);
+ if (c == 0x0a)
+ return 0;
+ if (c >= 0)
+ pdfi_unread_byte(ctx, s, (byte)c);
return 0;
}
+/* Fast(ish) but inaccurate strtof, with Adobe overflow handling,
+ * lifted from MuPDF. */
+static float acrobat_compatible_atof(char *s)
+{
+ int neg = 0;
+ int i = 0;
+
+ while (*s == '-') {
+ neg = 1;
+ ++s;
+ }
+ while (*s == '+') {
+ ++s;
+ }
+
+ while (*s >= '0' && *s <= '9') {
+ /* We deliberately ignore overflow here.
+ * Tests show that Acrobat handles * overflows in exactly the same way we do:
+ * 123450000000000000000678 is read as 678.
+ */
+ i = i * 10 + (*s - '0');
+ ++s;
+ }
+
+ if (*s == '.') {
+ float v = (float)i;
+ float n = 0;
+ float d = 1;
+ ++s;
+ while (*s >= '0' && *s <= '9') {
+ n = 10 * n + (*s - '0');
+ d = 10 * d;
+ ++s;
+ }
+ v += n / d;
+ return neg ? -v : v;
+ } else {
+ return (float)(neg ? -i : i);
+ }
+}
+
static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
{
byte Buffer[256];
- char Max[256];
- int MaxLen = 0;
unsigned short index = 0;
- short bytes;
bool real = false;
bool has_decimal_point = false;
bool has_exponent = false;
unsigned short exponent_index = 0;
pdf_num *num;
- int code = 0, malformed = false, doubleneg = false, recovered = false;
+ int code = 0, malformed = false, doubleneg = false, recovered = false, negative = false;
+ int int_val = 0;
pdfi_skip_white(ctx, s);
do {
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, s);
- if (bytes == 0 && s->eof) {
+ int c = pdfi_read_byte(ctx, s);
+ if (c == EOFC) {
Buffer[index] = 0x00;
break;
}
- if (bytes <= 0)
+ if (c < 0)
return_error(gs_error_ioerror);
- if (iswhite((char)Buffer[index])) {
+ if (iswhite(c)) {
+ Buffer[index] = 0x00;
+ break;
+ } else if (isdelimiter(c)) {
+ pdfi_unread_byte(ctx, s, (byte)c);
Buffer[index] = 0x00;
break;
- } else {
- if (isdelimiter((char)Buffer[index])) {
- pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- Buffer[index] = 0x00;
- break;
- }
}
- if (Buffer[index] == '.') {
+ Buffer[index] = (byte)c;
+
+ if (c >= '0' && c <= '9') {
+ if (!(malformed && recovered))
+ int_val = int_val*10 + c - '0';
+ } else if (c == '.') {
if (has_decimal_point == true) {
if (ctx->args.pdfstoponerror)
return_error(gs_error_syntaxerror);
@@ -191,7 +224,7 @@ static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_nu
has_decimal_point = true;
real = true;
}
- } else if (Buffer[index] == 'e' || Buffer[index] == 'E') {
+ } else if (c == 'e' || c == 'E') {
/* TODO: technically scientific notation isn't in PDF spec,
* but gs seems to accept it, so we should also?
*/
@@ -205,32 +238,47 @@ static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_nu
exponent_index = index;
real = true;
}
- } else if (Buffer[index] == '-' || Buffer[index] == '+') {
+ } else if (c == '-') {
+ /* Any - sign not at the start of the string, or just after an exponent
+ * indicates a malformed number. */
if (!(index == 0 || (has_exponent && index == exponent_index+1))) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", NULL);
if (ctx->args.pdfstoponerror)
return_error(gs_error_syntaxerror);
- /* Acrobat weirdness. We need to know if a number starts with two - signs
- * because Acrobat treats real and integers defined this way differently!
- * Double-negated integers are treated as 0, and reals are treated as if
- * they had one negative sign. We can't tell whether the number is a real
- * or not yet, we do that below.
- */
- pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", NULL);
- if (Buffer[index - 1] == '-') {
- doubleneg = true;
- index -= 1;
+ if (Buffer[index - 1] != '-') {
+ /* We are parsing a number line 123-56. We should continue parsing, but
+ * ignore anything from the second -. */
+ malformed = true;
+ Buffer[index] = 0;
+ recovered = true;
}
- else {
+ }
+ if (!has_exponent && !(malformed && recovered)) {
+ doubleneg = negative;
+ negative = 1;
+ }
+ } else if (c == '+') {
+ if (index == 0 || (has_exponent && index == exponent_index+1)) {
+ /* Just drop the + it's pointless, and it'll get in the way
+ * of our negation handling for floats. */
+ index--;
+ } else {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", NULL);
+ if (ctx->args.pdfstoponerror)
+ return_error(gs_error_syntaxerror);
+ if (Buffer[index - 1] != '-') {
+ /* We are parsing a number line 123-56. We should continue parsing, but
+ * ignore anything from the second -. */
malformed = true;
- Buffer[index] = 0x00;
+ Buffer[index] = 0;
recovered = true;
}
}
- } else if (Buffer[index] < 0x30 || Buffer[index] > 0x39) {
+ } else {
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGWHITESPACE, "pdfi_read_num", (char *)"Ignoring missing white space while parsing number");
if (ctx->args.pdfstoponerror)
return_error(gs_error_syntaxerror);
- pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
+ pdfi_unread_byte(ctx, s, (byte)c);
Buffer[index] = 0x00;
break;
}
@@ -238,38 +286,6 @@ static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_nu
return_error(gs_error_syntaxerror);
} while(1);
- if (!real && index > 7) {
- /* Check for integer overflow, represent as real if so */
- gs_sprintf(Max, "%d", (max_uint >> 1));
- MaxLen = strlen((const char *)Max);
-
- if (index >= MaxLen) {
- int j = 0;
-
- if (Buffer[j] == '-')
- j++;
-
- while (Buffer[j] == '0')
- j++;
-
- if (index - j > MaxLen)
- real = true;
-
- if (index - j == MaxLen)
- {
- real = false;
-
- for (;j< MaxLen; j++) {
- if (Buffer[j] == Max[j])
- continue;
- if (Buffer[j] > Max[j])
- real=true;
- break;
- }
- }
- }
- }
-
if (real && (!malformed || (malformed && recovered)))
code = pdfi_object_alloc(ctx, PDF_REAL, 0, (pdf_obj **)&num);
else
@@ -278,67 +294,21 @@ static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_nu
return code;
if ((malformed && !recovered) || (!real && doubleneg)) {
- char extra_info[gp_file_name_sizeof];
-
- gs_sprintf(extra_info, "Treating malformed number %s as 0", Buffer);
- pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", extra_info);
+ pdfi_set_error_var(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", "Treating malformed number %s as 0", Buffer);
num->value.i = 0;
- } else {
- if (real) {
- float tempf;
- char *dot = NULL, mfloat[256]; /* We limit numbers to 255 above so it can't exceed this */
-
- /* Check for overflow */
- gs_sprintf(mfloat, "%f", MAX_FLOAT);
- dot = strstr(mfloat, ".");
- *dot = 0x00;
-
- dot = strstr((char *)Buffer, ".");
- if (dot != NULL)
- *dot = 0x00;
- if (strlen((char *)Buffer) > strlen(mfloat)) {
- if (dot != NULL)
- *dot = '.';
- if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "overflow reading real number : %s\n", Buffer);
- pdfi_set_warning(ctx, 0, NULL, W_PDF_OVERFLOW_REAL, "pdfi_read_num", NULL);
- num->value.d = 0.0;
- }
- else {
- if (strlen((char *)Buffer) == strlen(mfloat)) {
- int fi = 0;
-
- for (fi = 0;fi < strlen((const char *)Buffer);fi++) {
- if (Buffer[fi] > mfloat[fi]) {
- if (dot != NULL)
- *dot = '.';
- if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "overflow reading real number : %s\n", Buffer);
- pdfi_set_warning(ctx, 0, NULL, W_PDF_OVERFLOW_REAL, "pdfi_read_num", NULL);
- num->value.d = 0.0;
- }
- }
- }
- if (dot != NULL)
- *dot = '.';
- if (sscanf((const char *)Buffer, "%f", &tempf) == 0) {
- if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "failed to read real number : %s\n", Buffer);
- pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_REAL, "pdfi_read_num", NULL);
- num->value.d = 0.0;
- }
- num->value.d = tempf;
- }
+ } else if (has_exponent) {
+ float f;
+ if (sscanf((char *)Buffer, "%g", &f) == 1) {
+ num->value.d = f;
} else {
- int tempi;
- if (sscanf((const char *)Buffer, "%d", &tempi) == 0) {
- if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "failed to read integer : %s\n", Buffer);
- gs_free_object(OBJ_MEMORY(num), num, "pdfi_read_num error");
- return_error(gs_error_syntaxerror);
- }
- num->value.i = tempi;
+ pdfi_set_error_var(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", "Treating malformed float %s as 0", Buffer);
+ num->value.d = 0;
}
+ } else if (real) {
+ num->value.d = acrobat_compatible_atof((char *)Buffer);
+ } else {
+ /* The doubleneg case is taken care of above. */
+ num->value.i = negative ? -int_val : int_val;
}
if (ctx->args.pdfdebug) {
if (real)
@@ -371,31 +341,29 @@ static int pdfi_read_name(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_n
return_error(gs_error_VMerror);
do {
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, s);
- if (bytes == 0 && s->eof)
+ int c = pdfi_read_byte(ctx, s);
+ if (c < 0)
break;
- if (bytes <= 0)
- return_error(gs_error_ioerror);
- if (iswhite((char)Buffer[index])) {
+ if (iswhite((char)c)) {
+ Buffer[index] = 0x00;
+ break;
+ } else if (isdelimiter((char)c)) {
+ pdfi_unread_byte(ctx, s, (char)c);
Buffer[index] = 0x00;
break;
- } else {
- if (isdelimiter((char)Buffer[index])) {
- pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- Buffer[index] = 0x00;
- break;
- }
}
+ Buffer[index] = (char)c;
/* Check for and convert escaped name characters */
- if (Buffer[index] == '#') {
+ if (c == '#') {
byte NumBuf[2];
bytes = pdfi_read_bytes(ctx, (byte *)&NumBuf, 1, 2, s);
if (bytes < 2 || (!ishex(NumBuf[0]) || !ishex(NumBuf[1]))) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_NAME_ESCAPE, "pdfi_read_name", NULL);
pdfi_unread(ctx, s, (byte *)NumBuf, bytes);
+ /* This leaves the name buffer with a # in it, rather than anything sane! */
}
else
Buffer[index] = (fromhex(NumBuf[0]) << 4) + fromhex(NumBuf[1]);
@@ -439,12 +407,11 @@ static int pdfi_read_name(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_n
static int pdfi_read_hexstring(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
{
- char *Buffer, *NewBuf = NULL, HexBuf[2];
+ char *Buffer, *NewBuf = NULL;
unsigned short index = 0;
- short bytes = 0;
uint32_t size = 256;
pdf_string *string = NULL;
- int code;
+ int code, hex0, hex1;
Buffer = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_read_hexstring");
if (Buffer == NULL)
@@ -455,44 +422,36 @@ static int pdfi_read_hexstring(pdf_context *ctx, pdf_c_stream *s, uint32_t indir
do {
do {
- bytes = pdfi_read_bytes(ctx, (byte *)HexBuf, 1, 1, s);
- if (bytes == 0 && s->eof)
+ hex0 = pdfi_read_byte(ctx, s);
+ if (hex0 < 0)
break;
- if (bytes <= 0) {
- code = gs_note_error(gs_error_ioerror);
- goto exit;
- }
- } while(iswhite(HexBuf[0]));
- if (bytes == 0 && s->eof)
+ } while(iswhite(hex0));
+ if (hex0 < 0)
break;
- if (HexBuf[0] == '>')
+ if (hex0 == '>')
break;
if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "%c", HexBuf[0]);
+ dmprintf1(ctx->memory, "%c", (char)hex0);
do {
- bytes = pdfi_read_bytes(ctx, (byte *)&HexBuf[1], 1, 1, s);
- if (bytes == 0 && s->eof)
+ hex1 = pdfi_read_byte(ctx, s);
+ if (hex1 < 0)
break;
- if (bytes <= 0) {
- code = gs_note_error(gs_error_ioerror);
- goto exit;
- }
- } while(iswhite(HexBuf[1]));
- if (bytes == 0 && s->eof)
+ } while(iswhite(hex1));
+ if (hex1 < 0)
break;
- if (!ishex(HexBuf[0]) || !ishex(HexBuf[1])) {
+ if (!ishex(hex0) || !ishex(hex1)) {
code = gs_note_error(gs_error_syntaxerror);
goto exit;
}
if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, "%c", HexBuf[1]);
+ dmprintf1(ctx->memory, "%c", (char)hex1);
- Buffer[index] = (fromhex(HexBuf[0]) << 4) + fromhex(HexBuf[1]);
+ Buffer[index] = (fromhex(hex0) << 4) + fromhex(hex1);
if (index++ >= size - 1) {
NewBuf = (char *)gs_alloc_bytes(ctx->memory, size + 256, "pdfi_read_hexstring");
@@ -534,12 +493,11 @@ static int pdfi_read_hexstring(pdf_context *ctx, pdf_c_stream *s, uint32_t indir
static int pdfi_read_string(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
{
- char *Buffer, *NewBuf = NULL, octal[3];
+ char *Buffer, *NewBuf = NULL;
unsigned short index = 0;
- short bytes = 0;
uint32_t size = 256;
pdf_string *string = NULL;
- int code, octal_index = 0, nesting = 0;
+ int c, code, nesting = 0;
bool escape = false, skip_eol = false, exit_loop = false;
Buffer = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_read_string");
@@ -559,140 +517,109 @@ static int pdfi_read_string(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect
size += 256;
}
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, s);
+ c = pdfi_read_byte(ctx, s);
- if (bytes == 0 && s->eof)
- break;
- if (bytes <= 0) {
+ if (c < 0) {
+ if (nesting > 0)
+ pdfi_set_error(ctx, 0, NULL, E_PDF_UNESCAPEDSTRING, "pdfi_read_string", NULL);
Buffer[index] = 0x00;
break;
}
if (skip_eol) {
- if (Buffer[index] == 0x0a || Buffer[index] == 0x0d)
+ if (c == 0x0a || c == 0x0d)
continue;
skip_eol = false;
}
+ Buffer[index] = (char)c;
if (escape) {
escape = false;
- if (Buffer[index] == 0x0a || Buffer[index] == 0x0d) {
- skip_eol = true;
- continue;
- }
- if (octal_index) {
- byte dummy[2];
- dummy[0] = '\\';
- dummy[1] = Buffer[index];
- code = pdfi_unread(ctx, s, dummy, 2);
- if (code < 0) {
- gs_free_object(ctx->memory, Buffer, "pdfi_read_string");
- return code;
- }
- Buffer[index] = octal[0];
- if (octal_index == 2)
- Buffer[index] = (Buffer[index] * 8) + octal[1];
- octal_index = 0;
- } else {
- switch (Buffer[index]) {
- case 'n':
- Buffer[index] = 0x0a;
- break;
- case 'r':
- Buffer[index] = 0x0d;
- break;
- case 't':
- Buffer[index] = 0x09;
- break;
- case 'b':
- Buffer[index] = 0x08;
- break;
- case 'f':
- Buffer[index] = 0x0c;
- break;
- case '(':
- case ')':
- case '\\':
- break;
- default:
- if (Buffer[index] >= 0x30 && Buffer[index] <= 0x37) {
- octal[octal_index] = Buffer[index] - 0x30;
- octal_index++;
- continue;
- }
- /* PDF Reference, literal strings, if the character following a
- * escape \ character is not recognised, then it is ignored.
- */
- escape = false;
- index++;
- continue;
- }
- }
- } else {
- switch(Buffer[index]) {
+ switch (Buffer[index]) {
case 0x0a:
case 0x0d:
- if (octal_index != 0) {
- code = pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- if (code < 0) {
- gs_free_object(ctx->memory, Buffer, "pdfi_read_string");
- return code;
- }
- Buffer[index] = octal[0];
- if (octal_index == 2)
- Buffer[index] = (Buffer[index] * 8) + octal[1];
- octal_index = 0;
- } else {
- Buffer[index] = 0x0a;
- skip_eol = true;
- }
+ skip_eol = true;
+ continue;
+ case 'n':
+ Buffer[index] = 0x0a;
+ break;
+ case 'r':
+ Buffer[index] = 0x0d;
+ break;
+ case 't':
+ Buffer[index] = 0x09;
+ break;
+ case 'b':
+ Buffer[index] = 0x08;
break;
+ case 'f':
+ Buffer[index] = 0x0c;
+ break;
+ case '(':
case ')':
- if (octal_index != 0) {
- code = pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- if (code < 0) {
- gs_free_object(ctx->memory, Buffer, "pdfi_read_string");
- return code;
- }
- Buffer[index] = octal[0];
- if (octal_index == 2)
- Buffer[index] = (Buffer[index] * 8) + octal[1];
- octal_index = 0;
+ case '\\':
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ /* Octal chars can be 1, 2 or 3 chars in length, terminated either
+ * by being 3 chars long, EOFC, or a non-octal char. We do not allow
+ * line breaks in the middle of octal chars. */
+ int c1 = pdfi_read_byte(ctx, s);
+ c -= '0';
+ if (c1 < 0) {
+ /* Nothing to do, or unread */
+ } else if (c1 < '0' || c1 > '7') {
+ pdfi_unread_byte(ctx, s, (char)c1);
} else {
- if (nesting == 0) {
- Buffer[index] = 0x00;
- exit_loop = true;
+ c = c*8 + c1 - '0';
+ c1 = pdfi_read_byte(ctx, s);
+ if (c1 < 0) {
+ /* Nothing to do, or unread */
+ } else if (c1 < '0' || c1 > '7') {
+ pdfi_unread_byte(ctx, s, (char)c1);
} else
- nesting--;
+ c = c*8 + c1 - '0';
}
+ Buffer[index] = c;
+ break;
+ }
+ default:
+ /* PDF Reference, literal strings, if the character following a
+ * escape \ character is not recognised, then it is ignored.
+ */
+ escape = false;
+ index++;
+ continue;
+ }
+ } else {
+ switch(Buffer[index]) {
+ case 0x0d:
+ Buffer[index] = 0x0a;
+ /*fallthrough*/
+ case 0x0a:
+ skip_eol = true;
+ break;
+ case ')':
+ if (nesting == 0) {
+ Buffer[index] = 0x00;
+ exit_loop = true;
+ } else
+ nesting--;
break;
case '\\':
escape = true;
continue;
case '(':
- pdfi_set_error(ctx, 0, NULL, E_PDF_UNESCAPEDSTRING, "pdfi_read_string", NULL);
nesting++;
break;
default:
- if (octal_index) {
- if (Buffer[index] >= 0x30 && Buffer[index] <= 0x37) {
- octal[octal_index] = Buffer[index] - 0x30;
- if (++octal_index < 3)
- continue;
- Buffer[index] = (octal[0] * 64) + (octal[1] * 8) + octal[2];
- octal_index = 0;
- } else {
- code = pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- if (code < 0) {
- gs_free_object(ctx->memory, Buffer, "pdfi_read_string");
- return code;
- }
- Buffer[index] = octal[0];
- if (octal_index == 2)
- Buffer[index] = (Buffer[index] * 8) + octal[1];
- octal_index = 0;
- }
- }
break;
}
}
@@ -744,6 +671,9 @@ int pdfi_read_dict(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uin
code = pdfi_read_token(ctx, s, indirect_num, indirect_gen);
if (code < 0)
return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
+
if (ctx->stack_top[-1]->type != PDF_DICT_MARK)
return_error(gs_error_typecheck);
depth = pdfi_count_stack(ctx);
@@ -752,32 +682,29 @@ int pdfi_read_dict(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uin
code = pdfi_read_token(ctx, s, indirect_num, indirect_gen);
if (code < 0)
return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
} while(pdfi_count_stack(ctx) > depth);
return 0;
}
int pdfi_skip_comment(pdf_context *ctx, pdf_c_stream *s)
{
- byte Buffer;
- short bytes = 0;
+ int c;
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, " %%");
do {
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer, 1, 1, s);
- if (bytes < 0)
- return_error(gs_error_ioerror);
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
+ break;
- if (bytes > 0) {
- if (ctx->args.pdfdebug)
- dmprintf1 (ctx->memory, " %c", Buffer);
+ if (ctx->args.pdfdebug)
+ dmprintf1 (ctx->memory, " %c", (char)c);
+
+ } while (c != 0x0a && c != 0x0d);
- if ((Buffer == 0x0A) || (Buffer == 0x0D)) {
- break;
- }
- }
- } while (bytes);
return 0;
}
@@ -791,30 +718,23 @@ static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirec
{
byte Buffer[256];
unsigned short index = 0;
- short bytes = 0;
- int code;
+ int c, code;
pdf_keyword *keyword;
pdfi_skip_white(ctx, s);
do {
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, s);
- if (bytes < 0)
- return_error(gs_error_ioerror);
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
+ break;
- if (bytes > 0) {
- if (iswhite(Buffer[index])) {
- pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- break;
- } else {
- if (isdelimiter(Buffer[index])) {
- pdfi_unread(ctx, s, (byte *)&Buffer[index], 1);
- break;
- }
- }
- index++;
+ if (iswhite(c) || isdelimiter(c)) {
+ pdfi_unread_byte(ctx, s, (byte)c);
+ break;
}
- } while (bytes && index < 255);
+ Buffer[index] = (byte)c;
+ index++;
+ } while (index < 255);
if (index >= 255 || index == 0) {
if (ctx->args.pdfstoponerror)
@@ -990,19 +910,18 @@ static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirec
*/
int pdfi_read_token(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
{
- int32_t bytes = 0;
- char Buffer[256];
- int code;
+ int c, code;
+rescan:
pdfi_skip_white(ctx, s);
- bytes = pdfi_read_bytes(ctx, (byte *)Buffer, 1, 1, s);
- if (bytes < 0)
- return (gs_error_ioerror);
- if (bytes == 0 && s->eof)
+ c = pdfi_read_byte(ctx, s);
+ if (c == EOFC)
return 0;
+ if (c < 0)
+ return_error(gs_error_ioerror);
- switch(Buffer[0]) {
+ switch(c) {
case 0x30:
case 0x31:
case 0x32:
@@ -1016,94 +935,112 @@ int pdfi_read_token(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, ui
case '+':
case '-':
case '.':
- pdfi_unread(ctx, s, (byte *)&Buffer[0], 1);
+ pdfi_unread_byte(ctx, s, (byte)c);
code = pdfi_read_num(ctx, s, indirect_num, indirect_gen);
if (code < 0)
return code;
break;
case '/':
- return pdfi_read_name(ctx, s, indirect_num, indirect_gen);
+ code = pdfi_read_name(ctx, s, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
+ return 1;
break;
case '<':
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[1], 1, 1, s);
- if (bytes <= 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return (gs_error_ioerror);
- if (iswhite(Buffer[1])) {
+ if (iswhite(c)) {
code = pdfi_skip_white(ctx, s);
if (code < 0)
return code;
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[1], 1, 1, s);
+ c = pdfi_read_byte(ctx, s);
}
- if (Buffer[1] == '<') {
+ if (c == '<') {
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, " <<\n");
- return pdfi_mark_stack(ctx, PDF_DICT_MARK);
- } else {
- if (Buffer[1] == '>') {
- pdfi_unread(ctx, s, (byte *)&Buffer[1], 1);
- return pdfi_read_hexstring(ctx, s, indirect_num, indirect_gen);
- } else {
- if (ishex(Buffer[1])) {
- pdfi_unread(ctx, s, (byte *)&Buffer[1], 1);
- return pdfi_read_hexstring(ctx, s, indirect_num, indirect_gen);
- }
- else
- return_error(gs_error_syntaxerror);
- }
+ code = pdfi_mark_stack(ctx, PDF_DICT_MARK);
+ if (code < 0)
+ return code;
+ return 1;
+ } else if (c == '>') {
+ pdfi_unread_byte(ctx, s, (byte)c);
+ code = pdfi_read_hexstring(ctx, s, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
+ return 1;
+ } else if (ishex(c)) {
+ pdfi_unread_byte(ctx, s, (byte)c);
+ code = pdfi_read_hexstring(ctx, s, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
}
+ else
+ return_error(gs_error_syntaxerror);
break;
case '>':
- bytes = pdfi_read_bytes(ctx, (byte *)&Buffer[1], 1, 1, s);
- if (bytes <= 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return (gs_error_ioerror);
- if (Buffer[1] == '>')
- return pdfi_dict_from_stack(ctx, indirect_num, indirect_gen);
- else {
- pdfi_unread(ctx, s, (byte *)&Buffer[1], 1);
+ if (c == '>') {
+ code = pdfi_dict_from_stack(ctx, indirect_num, indirect_gen, false);
+ if (code < 0)
+ return code;
+ return 1;
+ } else {
+ pdfi_unread_byte(ctx, s, (byte)c);
return_error(gs_error_syntaxerror);
}
break;
case '(':
- return pdfi_read_string(ctx, s, indirect_num, indirect_gen);
+ code = pdfi_read_string(ctx, s, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
+ return 1;
break;
case '[':
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, "[");
- return pdfi_mark_stack(ctx, PDF_ARRAY_MARK);
+ code = pdfi_mark_stack(ctx, PDF_ARRAY_MARK);
+ if (code < 0)
+ return code;
+ return 1;
break;
case ']':
code = pdfi_array_from_stack(ctx, indirect_num, indirect_gen);
- if (code < 0) {
- if (code == gs_error_VMerror || code == gs_error_ioerror || ctx->args.pdfstoponerror)
- return code;
- pdfi_clearstack(ctx);
- return pdfi_read_token(ctx, s, indirect_num, indirect_gen);
- }
+ if (code < 0)
+ return code;
break;
case '{':
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, "{");
- return pdfi_mark_stack(ctx, PDF_PROC_MARK);
+ code = pdfi_mark_stack(ctx, PDF_PROC_MARK);
+ if (code < 0)
+ return code;
+ return 1;
break;
case '}':
pdfi_clear_to_mark(ctx);
- return pdfi_read_token(ctx, s, indirect_num, indirect_gen);
+ goto rescan;
break;
case '%':
pdfi_skip_comment(ctx, s);
- return pdfi_read_token(ctx, s, indirect_num, indirect_gen);
+ goto rescan;
break;
default:
- if (isdelimiter(Buffer[0])) {
+ if (isdelimiter(c)) {
if (ctx->args.pdfstoponerror)
return_error(gs_error_syntaxerror);
- return pdfi_read_token(ctx, s, indirect_num, indirect_gen);
+ goto rescan;
}
- pdfi_unread(ctx, s, (byte *)&Buffer[0], 1);
- return pdfi_read_keyword(ctx, s, indirect_num, indirect_gen);
+ pdfi_unread_byte(ctx, s, (byte)c);
+ code = pdfi_read_keyword(ctx, s, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
+ return 1;
break;
}
- return 0;
+ return 1;
}
/* In contrast to the 'read' functions, the 'make' functions create an object with a
@@ -1183,7 +1120,7 @@ static int search_table_1(pdf_context *ctx, unsigned char *str, pdf_keyword **ke
{
int i, code = 0;
- for (i = 0; i < 39; i++) {
+ for (i = 0; i < 27; i++) {
if (memcmp(str, op_table_1[i], 1) == 0) {
code = pdfi_object_alloc(ctx, PDF_KEYWORD, 1, (pdf_obj **)key);
if (code < 0)
@@ -1316,29 +1253,21 @@ static int split_bogus_operator(pdf_context *ctx, pdf_c_stream *source, pdf_dict
if (code <= 0)
goto error_exit;
- if (code > 0) {
- switch(keyword->length - 1) {
- case 1:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
- break;
- case 2:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
- break;
- case 3:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
- break;
- default:
- goto error_exit;
- }
- if (code <= 0)
+ switch(keyword->length - 1) {
+ case 1:
+ code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ break;
+ case 2:
+ code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ break;
+ case 3:
+ code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ break;
+ default:
goto error_exit;
- if (code > 0)
- goto match;
}
- pdfi_countdown(key1);
- pdfi_countdown(key2);
- key1 = NULL;
- key2 = NULL;
+ if (code <= 0)
+ goto error_exit;
match:
/* If we get here, we have two PDF_KEYWORD objects. We push them on the stack
@@ -1448,10 +1377,6 @@ static int pdfi_interpret_stream_operator(pdf_context *ctx, pdf_c_stream *source
pdfi_pop(ctx, 1);
code = pdfi_setdash(ctx);
break;
- case K2('E','I'): /* end inline image */
- pdfi_pop(ctx, 1);
- code = pdfi_EI(ctx);
- break;
case K2('d','0'): /* set type 3 font glyph width */
pdfi_pop(ctx, 1);
code = pdfi_d0(ctx);
@@ -1466,10 +1391,11 @@ static int pdfi_interpret_stream_operator(pdf_context *ctx, pdf_c_stream *source
break;
case K2('D','P'): /* define marked content point with property list */
pdfi_pop(ctx, 1);
- if (pdfi_count_stack(ctx) >= 2) {
- pdfi_pop(ctx, 2);
- } else
- pdfi_clearstack(ctx);
+ code = pdfi_op_DP(ctx, stream_dict, page_dict);
+ break;
+ case K2('E','I'): /* end inline image */
+ pdfi_pop(ctx, 1);
+ code = pdfi_EI(ctx);
break;
case K2('E','T'): /* end text */
pdfi_pop(ctx, 1);
@@ -1548,8 +1474,7 @@ static int pdfi_interpret_stream_operator(pdf_context *ctx, pdf_c_stream *source
break;
case K2('M','P'): /* define marked content point */
pdfi_pop(ctx, 1);
- if (pdfi_count_stack(ctx) >= 1)
- pdfi_pop(ctx, 1);
+ code = pdfi_op_MP(ctx);
break;
case K1('n'): /* newpath */
pdfi_pop(ctx, 1);
@@ -1763,86 +1688,12 @@ void initialise_stream_save(pdf_context *ctx)
ctx->current_stream_save.stack_count = pdfi_count_total_stack(ctx);
}
-static int setup_stream_DefaultSpaces(pdf_context *ctx, pdf_dict *stream_dict)
-{
- int code = 0;
- pdf_dict *resources_dict = NULL, *colorspaces_dict = NULL;
- pdf_obj *DefaultSpace = NULL;
-
- /* Create any required DefaultGray, DefaultRGB or DefaultCMYK
- * spaces.
- */
-
- if (ctx->args.NOSUBSTDEVICECOLORS)
- return 0;
-
- code = pdfi_dict_knownget(ctx, stream_dict, "Resources", (pdf_obj **)&resources_dict);
- if (code > 0) {
- code = pdfi_dict_knownget(ctx, resources_dict, "ColorSpace", (pdf_obj **)&colorspaces_dict);
- if (code > 0) {
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultGray", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, stream_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space (or page level Default) instead, this is as per the spec.
- */
- if (code >= 0) {
- if (ctx->page.DefaultGray_cs)
- rc_decrement_only(ctx->page.DefaultGray_cs, "setup_stream_DefaultSpaces");
- ctx->page.DefaultGray_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultRGB", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, stream_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space (or page level Default) instead, this is as per the spec.
- */
- if (code >= 0) {
- if (ctx->page.DefaultRGB_cs)
- rc_decrement_only(ctx->page.DefaultRGB_cs, "setup_stream_DefaultSpaces");
- ctx->page.DefaultRGB_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultCMYK", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, stream_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space (or page level Default) instead, this is as per the spec.
- */
- if (code >= 0) {
- if (ctx->page.DefaultCMYK_cs)
- rc_decrement_only(ctx->page.DefaultCMYK_cs, "setup_stream_DefaultSpaces");
- ctx->page.DefaultCMYK_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- }
- }
-
- pdfi_countdown(DefaultSpace);
- pdfi_countdown(resources_dict);
- pdfi_countdown(colorspaces_dict);
- return 0;
-}
-
/* Run a stream in a sub-context (saves/restores DefaultQState) */
int pdfi_run_context(pdf_context *ctx, pdf_stream *stream_obj,
pdf_dict *page_dict, bool stoponerror, const char *desc)
{
- int code;
- gs_gstate *DefaultQState;
+ int code = 0, code1 = 0;
+ gs_gstate *DefaultQState = NULL;
/* Save any existing Default* colour spaces */
gs_color_space *PageDefaultGray = ctx->page.DefaultGray_cs;
gs_color_space *PageDefaultRGB = ctx->page.DefaultRGB_cs;
@@ -1859,12 +1710,29 @@ int pdfi_run_context(pdf_context *ctx, pdf_stream *stream_obj,
/* If the stream has any Default* colour spaces, replace the page level ones.
* This will derement the reference counts to the current spaces if they are replaced.
*/
- setup_stream_DefaultSpaces(ctx, stream_obj->stream_dict);
+ code = pdfi_setup_DefaultSpaces(ctx, stream_obj->stream_dict);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_copy_DefaultQState(ctx, &DefaultQState);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_set_DefaultQState(ctx, ctx->pgs);
+ if (code < 0)
+ goto exit;
- pdfi_copy_DefaultQState(ctx, &DefaultQState);
- pdfi_set_DefaultQState(ctx, ctx->pgs);
code = pdfi_interpret_inner_content_stream(ctx, stream_obj, page_dict, stoponerror, desc);
- pdfi_restore_DefaultQState(ctx, &DefaultQState);
+
+ code1 = pdfi_restore_DefaultQState(ctx, &DefaultQState);
+ if (code >= 0)
+ code = code1;
+
+exit:
+ if (DefaultQState != NULL) {
+ gs_gstate_free(DefaultQState);
+ DefaultQState = NULL;
+ }
/* Count down any Default* colour spaces */
rc_decrement(ctx->page.DefaultGray_cs, "pdfi_run_context");
@@ -2031,6 +1899,24 @@ pdfi_interpret_content_stream(pdf_context *ctx, pdf_c_stream *content_stream,
int code;
pdf_c_stream *stream;
pdf_keyword *keyword;
+ pdf_stream *s = ctx->current_stream;
+
+ /* Check this stream, and all the streams currently being executed, to see
+ * if the stream we've been given is already in train. If it is, then we
+ * have encountered recursion. This can happen if a non-page stream such
+ * as a Form or Pattern uses a Resource, but does not declare it in it's
+ * Resources, and instead inherits it from the parent. We cannot detect that
+ * before the Resource is used, so all we can do is check here.
+ */
+ while (s != NULL && s->type == PDF_STREAM) {
+ if (s->object_num > 0) {
+ if (s->object_num == stream_obj->object_num) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_CIRCULARREF, "pdfi_interpret_content_stream", "Aborting stream");
+ return_error(gs_error_circular_reference);
+ }
+ }
+ s = (pdf_stream *)s->parent_obj;
+ }
if (content_stream != NULL) {
stream = content_stream;
diff --git a/pdf/pdf_loop_detect.c b/pdf/pdf_loop_detect.c
index 7d08b182..7ba05987 100644
--- a/pdf/pdf_loop_detect.c
+++ b/pdf/pdf_loop_detect.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -84,7 +84,7 @@ bool pdfi_loop_detector_check_object(pdf_context *ctx, uint64_t object)
for (i=0;i < ctx->loop_detection_entries;i++) {
if (ctx->loop_detection[i] == object) {
char info_string[256];
- gs_sprintf(info_string, "Error! circular reference to object %"PRIu64" detected.\n", object);
+ gs_snprintf(info_string, sizeof(info_string), "Error! circular reference to object %"PRIu64" detected.\n", object);
pdfi_set_error(ctx, 0, NULL, E_PDF_CIRCULARREF, "pdfi_loop_detector_check_object", info_string);
return true;
}
diff --git a/pdf/pdf_mark.c b/pdf/pdf_mark.c
index 4f678f10..d625e34a 100644
--- a/pdf/pdf_mark.c
+++ b/pdf/pdf_mark.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -29,7 +29,7 @@
#include "gscoord.h" /* For gs_currentmatrix */
-static int pdfi_mark_setparam_obj(pdf_context *ctx, pdf_obj *obj, gs_param_string *entry)
+static int pdfi_pdfmark_setparam_obj(pdf_context *ctx, pdf_obj *obj, gs_param_string *entry)
{
int code = 0;
byte *data = NULL;
@@ -44,7 +44,7 @@ static int pdfi_mark_setparam_obj(pdf_context *ctx, pdf_obj *obj, gs_param_strin
return 0;
}
-static int pdfi_mark_setparam_pair(pdf_context *ctx, pdf_name *Key, pdf_obj *Value,
+static int pdfi_pdfmark_setparam_pair(pdf_context *ctx, pdf_name *Key, pdf_obj *Value,
gs_param_string *entry)
{
int code = 0;
@@ -55,11 +55,11 @@ static int pdfi_mark_setparam_pair(pdf_context *ctx, pdf_name *Key, pdf_obj *Val
goto exit;
}
- code = pdfi_mark_setparam_obj(ctx, (pdf_obj *)Key, entry);
+ code = pdfi_pdfmark_setparam_obj(ctx, (pdf_obj *)Key, entry);
if (code < 0)
goto exit;
- code = pdfi_mark_setparam_obj(ctx, Value, entry+1);
+ code = pdfi_pdfmark_setparam_obj(ctx, Value, entry+1);
if (code < 0)
goto exit;
@@ -69,12 +69,12 @@ static int pdfi_mark_setparam_pair(pdf_context *ctx, pdf_name *Key, pdf_obj *Val
/* Note: this isn't part of the obj_to_string() stuff */
-static int pdfi_mark_ctm_str(pdf_context *ctx, gs_matrix *ctm, byte **data, int *len)
+static int pdfi_pdfmark_ctm_str(pdf_context *ctx, gs_matrix *ctm, byte **data, int *len)
{
int size = 100;
char *buf;
- buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_mark_ctm_str(data)");
+ buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_pdfmark_ctm_str(data)");
if (buf == NULL)
return_error(gs_error_VMerror);
snprintf(buf, size, "[%.4f %.4f %.4f %.4f %.4f %.4f]",
@@ -85,7 +85,7 @@ static int pdfi_mark_ctm_str(pdf_context *ctx, gs_matrix *ctm, byte **data, int
}
/* Write an string array command to the device (e.g. pdfmark) */
-static int pdfi_mark_write_array(pdf_context *ctx, gs_param_string_array *array_list, const char *command)
+static int pdfi_pdfmark_write_array(pdf_context *ctx, gs_param_string_array *array_list, const char *command)
{
gs_c_param_list list;
int code;
@@ -117,7 +117,7 @@ static int pdfi_mark_write_array(pdf_context *ctx, gs_param_string_array *array_
}
/* Write an string array command to the device (e.g. pdfmark) */
-static int pdfi_mark_write_string(pdf_context *ctx, gs_param_string *param_string, const char *command)
+static int pdfi_pdfmark_write_string(pdf_context *ctx, gs_param_string *param_string, const char *command)
{
gs_c_param_list list;
int code;
@@ -162,7 +162,7 @@ static int pdfi_mark_write_string(pdf_context *ctx, gs_param_string *param_strin
See plparams.c/process_pdfmark()
*/
-static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *label,
+static int pdfi_pdfmark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *label,
pdf_dict *dict, gs_matrix *ctm, const char *type)
{
int code = 0;
@@ -193,7 +193,7 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
size += 1;
parray = (gs_param_string *)gs_alloc_bytes(ctx->memory, size*sizeof(gs_param_string),
- "pdfi_mark_from_dict(parray)");
+ "pdfi_pdfmark_from_dict(parray)");
if (parray == NULL) {
code = gs_note_error(gs_error_VMerror);
goto exit;
@@ -201,7 +201,7 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
memset(parray, 0, size*sizeof(gs_param_string));
if (label) {
- code = pdfi_mark_setparam_obj(ctx, (pdf_obj *)label, parray+0);
+ code = pdfi_pdfmark_setparam_obj(ctx, (pdf_obj *)label, parray+0);
offset += 1;
}
@@ -212,7 +212,7 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
code = pdfi_dict_get_no_deref(ctx, dict, Key, &Value);
if (code < 0) goto exit;
- code = pdfi_mark_setparam_pair(ctx, Key, Value, parray+offset+(keynum*2));
+ code = pdfi_pdfmark_setparam_pair(ctx, Key, Value, parray+offset+(keynum*2));
if (code < 0) goto exit;
pdfi_countdown(Key);
@@ -233,7 +233,7 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
if (code < 0) goto exit;
/* CTM */
- code = pdfi_mark_ctm_str(ctx, ctm, &ctm_data, &ctm_len);
+ code = pdfi_pdfmark_ctm_str(ctx, ctm, &ctm_data, &ctm_len);
if (code < 0) goto exit;
parray[size-2].data = ctm_data;
parray[size-2].size = ctm_len;
@@ -246,7 +246,7 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
array_list.persistent = false;
array_list.size = size;
- code = pdfi_mark_write_array(ctx, &array_list, "pdfmark");
+ code = pdfi_pdfmark_write_array(ctx, &array_list, "pdfmark");
exit:
pdfi_countdown(Key);
@@ -256,25 +256,25 @@ static int pdfi_mark_from_dict_withlabel(pdf_context *ctx, pdf_indirect_ref *lab
/* Free the param data except the last two which are handled separately */
for (i=0; i<size-2; i++) {
if (parray[i].data)
- gs_free_object(ctx->memory, (byte *)parray[i].data, "pdfi_mark_from_dict(parray)");
+ gs_free_object(ctx->memory, (byte *)parray[i].data, "pdfi_pdfmark_from_dict(parray)");
}
}
if (ctm_data)
- gs_free_object(ctx->memory, ctm_data, "pdfi_mark_from_dict(ctm_data)");
- gs_free_object(ctx->memory, parray, "pdfi_mark_from_dict(parray)");
+ gs_free_object(ctx->memory, ctm_data, "pdfi_pdfmark_from_dict(ctm_data)");
+ gs_free_object(ctx->memory, parray, "pdfi_pdfmark_from_dict(parray)");
return code;
}
/* Do a pdfmark from a dictionary */
-int pdfi_mark_from_dict(pdf_context *ctx, pdf_dict *dict, gs_matrix *ctm, const char *type)
+int pdfi_pdfmark_from_dict(pdf_context *ctx, pdf_dict *dict, gs_matrix *ctm, const char *type)
{
- return pdfi_mark_from_dict_withlabel(ctx, NULL, dict, ctm, type);
+ return pdfi_pdfmark_from_dict_withlabel(ctx, NULL, dict, ctm, type);
}
/* Does a pdfmark, from a c-array of pdf_obj's
* This will put in a dummy ctm if none provided
*/
-static int pdfi_mark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len,
+int pdfi_pdfmark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len,
gs_matrix *ctm, const char *type)
{
int code = 0;
@@ -295,7 +295,7 @@ static int pdfi_mark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len
size = len + 2; /* data + CTM + type */
parray = (gs_param_string *)gs_alloc_bytes(ctx->memory, size*sizeof(gs_param_string),
- "pdfi_mark_from_objarray(parray)");
+ "pdfi_pdfmark_from_objarray(parray)");
if (parray == NULL) {
code = gs_note_error(gs_error_VMerror);
goto exit;
@@ -303,12 +303,12 @@ static int pdfi_mark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len
memset(parray, 0, size *sizeof(gs_param_string));
for (i=0; i<len; i++) {
- code = pdfi_mark_setparam_obj(ctx, objarray[i], parray+i);
+ code = pdfi_pdfmark_setparam_obj(ctx, objarray[i], parray+i);
if (code < 0) goto exit;
}
/* CTM */
- code = pdfi_mark_ctm_str(ctx, ctm, &ctm_data, &ctm_len);
+ code = pdfi_pdfmark_ctm_str(ctx, ctm, &ctm_data, &ctm_len);
if (code < 0) goto exit;
parray[len].data = ctm_data;
parray[len].size = ctm_len;
@@ -321,24 +321,24 @@ static int pdfi_mark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len
array_list.persistent = false;
array_list.size = size;
- code = pdfi_mark_write_array(ctx, &array_list, "pdfmark");
+ code = pdfi_pdfmark_write_array(ctx, &array_list, "pdfmark");
exit:
if (parray != NULL) {
for (i=0; i<len; i++) {
- gs_free_object(ctx->memory, (byte *)parray[i].data, "pdfi_mark_from_objarray(parray)");
+ gs_free_object(ctx->memory, (byte *)parray[i].data, "pdfi_pdfmark_from_objarray(parray)");
}
}
if (ctm_data)
- gs_free_object(ctx->memory, ctm_data, "pdfi_mark_from_objarray(ctm_data)");
- gs_free_object(ctx->memory, parray, "pdfi_mark_from_objarray(parray)");
+ gs_free_object(ctx->memory, ctm_data, "pdfi_pdfmark_from_objarray(ctm_data)");
+ gs_free_object(ctx->memory, parray, "pdfi_pdfmark_from_objarray(parray)");
return code;
}
/* Send an arbitrary object as a string, with command 'cmd'
* This is not a pdfmark, has no ctm.
*/
-int pdfi_mark_object(pdf_context *ctx, pdf_obj *object, const char *cmd)
+int pdfi_pdfmark_object(pdf_context *ctx, pdf_obj *object, const char *cmd)
{
gs_param_string param_string;
int code = 0;
@@ -348,27 +348,21 @@ int pdfi_mark_object(pdf_context *ctx, pdf_obj *object, const char *cmd)
code = pdfi_loop_detector_mark(ctx);
if (code < 0)
goto exit;
- if (object->object_num != 0) {
- code = pdfi_loop_detector_add_object(ctx, object->object_num);
- if (code < 0) {
- (void)pdfi_loop_detector_cleartomark(ctx);
- goto exit;
- }
- }
- code = pdfi_resolve_indirect(ctx, object, true);
+
+ code = pdfi_resolve_indirect_loop_detect(ctx, NULL, object, true);
(void)pdfi_loop_detector_cleartomark(ctx);
if (code < 0)
goto exit;
- code = pdfi_mark_setparam_obj(ctx, object, &param_string);
+ code = pdfi_pdfmark_setparam_obj(ctx, object, &param_string);
if (code < 0)
goto exit;
- code = pdfi_mark_write_string(ctx, &param_string, cmd);
+ code = pdfi_pdfmark_write_string(ctx, &param_string, cmd);
exit:
if (param_string.data != NULL)
- gs_free_object(ctx->memory, (byte *)param_string.data, "free data transferred to param_string in pdfi_mark_object\n");
+ gs_free_object(ctx->memory, (byte *)param_string.data, "free data transferred to param_string in pdfi_pdfmark_object\n");
return code;
}
@@ -380,7 +374,7 @@ exit:
* Removes /Dest and inserts two key pairs: /Page N and /View <view_info>
* N is the page number, which starts at 1, not 0.
*/
-static int pdfi_mark_add_Page_View(pdf_context *ctx, pdf_dict *link_dict, pdf_array *dest_array)
+static int pdfi_pdfmark_add_Page_View(pdf_context *ctx, pdf_dict *link_dict, pdf_array *dest_array)
{
int code = 0;
int i;
@@ -437,7 +431,7 @@ static int pdfi_mark_add_Page_View(pdf_context *ctx, pdf_dict *link_dict, pdf_ar
}
/* Lookup a Dest string(or name) in the Names array and try to resolve it */
-static int pdfi_mark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
+static int pdfi_pdfmark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
pdf_obj *dest, pdf_array *Names)
{
int code = 0;
@@ -484,21 +478,26 @@ static int pdfi_mark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
goto exit;
}
- /* Next entry is supposed to be a dict */
+ /* Next entry is either a dictionary (with a /D key) or an array */
code = pdfi_array_get(ctx, Names, i+1, (pdf_obj **)&D_dict);
if (code < 0) goto exit;
- if (D_dict->type != PDF_DICT) {
- /* TODO: flag a warning? */
- code = 0;
- goto exit;
- }
- /* Dict is supposed to contain key "D" with Dest array */
- code = pdfi_dict_knownget_type(ctx, D_dict, "D", PDF_ARRAY, (pdf_obj **)&dest_array);
- if (code <= 0) goto exit;
+ if (D_dict->type == PDF_DICT) {
+ /* Dict is supposed to contain key "D" with Dest array */
+ code = pdfi_dict_knownget_type(ctx, D_dict, "D", PDF_ARRAY, (pdf_obj **)&dest_array);
+ if (code <= 0) goto exit;
+ } else {
+ if (D_dict->type == PDF_ARRAY) {
+ dest_array = (pdf_array *)D_dict;
+ D_dict = NULL;
+ } else {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ }
/* Process the dest_array to replace with /Page /View */
- code = pdfi_mark_add_Page_View(ctx, link_dict, dest_array);
+ code = pdfi_pdfmark_add_Page_View(ctx, link_dict, dest_array);
if (code < 0) goto exit;
exit:
@@ -511,7 +510,7 @@ static int pdfi_mark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
/* Special handling for "Dest" in Links
* Will replace /Dest with /Page /View in link_dict (for pdfwrite)
*/
-int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *link_dict)
+int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
{
int code = 0;
pdf_dict *Dests = NULL;
@@ -532,7 +531,7 @@ int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *link_dict)
switch (Dest->type) {
case PDF_ARRAY:
- code = pdfi_mark_add_Page_View(ctx, link_dict, (pdf_array *)Dest);
+ code = pdfi_pdfmark_add_Page_View(ctx, link_dict, (pdf_array *)Dest);
if (code < 0) goto exit;
break;
case PDF_NAME:
@@ -550,7 +549,7 @@ int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *link_dict)
code = gs_note_error(gs_error_typecheck);
goto exit;
}
- code = pdfi_mark_add_Page_View(ctx, link_dict, dest_array);
+ code = pdfi_pdfmark_add_Page_View(ctx, link_dict, dest_array);
if (code < 0) goto exit;
} else if (Names_dict != NULL) {
/* Looking in Catalog(Root) for /Names<</Dests<</Names [name dict array]>>>> */
@@ -567,7 +566,7 @@ int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *link_dict)
/* TODO: Not found -- not sure if there is another case here or not */
goto exit;
}
- code = pdfi_mark_handle_dest_names(ctx, link_dict, Dest, Names);
+ code = pdfi_pdfmark_handle_dest_names(ctx, link_dict, Dest, Names);
if (code < 0) goto exit;
} else {
/* TODO: Ignore it -- flag a warning? */
@@ -595,7 +594,7 @@ int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *link_dict)
/* Special handling for "A" in Link annotations and Outlines
* Will delete A if handled and if A_key is provided.
*/
-int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict)
+int pdfi_pdfmark_modA(pdf_context *ctx, pdf_dict *dict)
{
int code = 0;
pdf_dict *A_dict = NULL;
@@ -620,7 +619,7 @@ int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict)
code = pdfi_dict_known(ctx, A_dict, "URI", &known);
if (code < 0) goto exit;
if (known) {
- code = pdfi_resolve_indirect_loop_detect(ctx, (pdf_obj *)NULL, (pdf_obj *)dict, true);
+ code = pdfi_resolve_indirect_loop_detect(ctx, (pdf_obj *)NULL, (pdf_obj *)A_dict, true);
goto exit;
}
@@ -646,7 +645,7 @@ int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict)
goto exit;
}
/* Process the D array to replace with /Page /View */
- code = pdfi_mark_add_Page_View(ctx, dict, D_array);
+ code = pdfi_pdfmark_add_Page_View(ctx, dict, D_array);
if (code < 0) goto exit;
delete_A = true;
} else if (pdfi_name_is(S_name, "GoToR") || pdfi_name_is(S_name, "Launch")) {
@@ -713,7 +712,6 @@ int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict)
} else if (deref_A) {
pdfi_countdown(A_dict);
A_dict = NULL;
- code = pdfi_dict_get(ctx, dict, "A", (pdf_obj **)&A_dict);
}
pdfi_countdown(A_dict);
pdfi_countdown(S_name);
@@ -725,7 +723,7 @@ int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict)
* Send an OBJ (_objdef) command
* (_objdef) (<label>) (/type) (/<type>) OBJ
*/
-static int pdfi_mark_objdef_begin(pdf_context *ctx, pdf_indirect_ref *label, const char *type)
+static int pdfi_pdfmark_objdef_begin(pdf_context *ctx, pdf_indirect_ref *label, const char *type)
{
int code;
pdf_obj *objarray[4];
@@ -746,7 +744,7 @@ static int pdfi_mark_objdef_begin(pdf_context *ctx, pdf_indirect_ref *label, con
code = pdfi_obj_charstr_to_name(ctx, type, (pdf_name **)&objarray[3]);
if (code < 0) goto exit;
- code = pdfi_mark_from_objarray(ctx, objarray, num_objects, NULL, "OBJ");
+ code = pdfi_pdfmark_from_objarray(ctx, objarray, num_objects, NULL, "OBJ");
if (code < 0) goto exit;
exit:
@@ -759,7 +757,7 @@ static int pdfi_mark_objdef_begin(pdf_context *ctx, pdf_indirect_ref *label, con
* Send a CLOSE command
* (<label>) CLOSE
*/
-static int pdfi_mark_objdef_close(pdf_context *ctx, pdf_indirect_ref *label)
+static int pdfi_pdfmark_objdef_close(pdf_context *ctx, pdf_indirect_ref *label)
{
int code;
pdf_obj *objarray[1];
@@ -771,7 +769,7 @@ static int pdfi_mark_objdef_close(pdf_context *ctx, pdf_indirect_ref *label)
objarray[0] = (pdf_obj *)label;
pdfi_countup(label);
- code = pdfi_mark_from_objarray(ctx, objarray, num_objects, NULL, "CLOSE");
+ code = pdfi_pdfmark_from_objarray(ctx, objarray, num_objects, NULL, "CLOSE");
if (code < 0) goto exit;
exit:
@@ -780,7 +778,7 @@ static int pdfi_mark_objdef_close(pdf_context *ctx, pdf_indirect_ref *label)
return code;
}
-static int pdfi_mark_stream_contents(pdf_context *ctx, pdf_indirect_ref *label, pdf_stream *stream)
+static int pdfi_pdfmark_stream_contents(pdf_context *ctx, pdf_indirect_ref *label, pdf_stream *stream)
{
int code;
pdf_obj *objarray[2];
@@ -794,7 +792,7 @@ static int pdfi_mark_stream_contents(pdf_context *ctx, pdf_indirect_ref *label,
pdfi_countup(stream);
stream->is_marking = true;
- code = pdfi_mark_from_objarray(ctx, objarray, num_objects, NULL, ".PUTSTREAM");
+ code = pdfi_pdfmark_from_objarray(ctx, objarray, num_objects, NULL, ".PUTSTREAM");
if (code < 0) goto exit;
exit:
@@ -805,7 +803,7 @@ static int pdfi_mark_stream_contents(pdf_context *ctx, pdf_indirect_ref *label,
}
/* Mark a stream object */
-int pdfi_mark_stream(pdf_context *ctx, pdf_stream *stream)
+int pdfi_pdfmark_stream(pdf_context *ctx, pdf_stream *stream)
{
int code;
pdf_dict *streamdict = NULL;
@@ -858,16 +856,16 @@ int pdfi_mark_stream(pdf_context *ctx, pdf_stream *stream)
}
if (code < 0) goto exit;
- code = pdfi_mark_objdef_begin(ctx, streamref, "stream");
+ code = pdfi_pdfmark_objdef_begin(ctx, streamref, "stream");
if (code < 0) goto exit;
- code = pdfi_mark_from_dict_withlabel(ctx, streamref, tempdict, NULL, ".PUTDICT");
+ code = pdfi_pdfmark_from_dict_withlabel(ctx, streamref, tempdict, NULL, ".PUTDICT");
if (code < 0) goto exit;
- code = pdfi_mark_stream_contents(ctx, streamref, stream);
+ code = pdfi_pdfmark_stream_contents(ctx, streamref, stream);
if (code < 0) goto exit;
- code = pdfi_mark_objdef_close(ctx, streamref);
+ code = pdfi_pdfmark_objdef_close(ctx, streamref);
if (code < 0) goto exit;
exit:
@@ -877,7 +875,7 @@ int pdfi_mark_stream(pdf_context *ctx, pdf_stream *stream)
}
/* Mark a dict object */
-int pdfi_mark_dict(pdf_context *ctx, pdf_dict *dict)
+int pdfi_pdfmark_dict(pdf_context *ctx, pdf_dict *dict)
{
int code;
pdf_indirect_ref *dictref = NULL;
@@ -898,10 +896,10 @@ int pdfi_mark_dict(pdf_context *ctx, pdf_dict *dict)
dictref->ref_generation_num = dict->generation_num;
dictref->is_marking = true;
- code = pdfi_mark_objdef_begin(ctx, dictref, "dict");
+ code = pdfi_pdfmark_objdef_begin(ctx, dictref, "dict");
if (code < 0) goto exit;
- code = pdfi_mark_from_dict_withlabel(ctx, dictref, dict, NULL, ".PUTDICT");
+ code = pdfi_pdfmark_from_dict_withlabel(ctx, dictref, dict, NULL, ".PUTDICT");
if (code < 0) goto exit;
exit:
@@ -909,7 +907,7 @@ int pdfi_mark_dict(pdf_context *ctx, pdf_dict *dict)
return code;
}
-static int pdfi_mark_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec)
+static int pdfi_pdfmark_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec)
{
int code;
pdf_dict *tempdict = NULL;
@@ -928,7 +926,7 @@ static int pdfi_mark_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *file
code = pdfi_dict_put(ctx, tempdict, "FS", (pdf_obj *)filespec);
if (code < 0) goto exit;
- code = pdfi_mark_from_dict(ctx, tempdict, NULL, "EMBED");
+ code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "EMBED");
if (code < 0) goto exit;
exit:
@@ -937,11 +935,11 @@ static int pdfi_mark_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *file
}
/* embed a file */
-int pdfi_mark_embed_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec)
+int pdfi_pdfmark_embed_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec)
{
int code;
- code = pdfi_mark_filespec(ctx, name, filespec);
+ code = pdfi_pdfmark_filespec(ctx, name, filespec);
if (code < 0) goto exit;
exit:
@@ -952,7 +950,7 @@ int pdfi_mark_embed_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *files
* Create and emit a /DOCINFO pdfmark for any and all of Title,
* Author, Subject, Keywords and Creator
*/
-void pdfi_write_docinfo_pdfmark(pdf_context *ctx, pdf_dict *info_dict)
+void pdfi_pdfmark_write_docinfo(pdf_context *ctx, pdf_dict *info_dict)
{
int i, code = 0;
pdf_dict *Info = NULL;
@@ -972,14 +970,14 @@ void pdfi_write_docinfo_pdfmark(pdf_context *ctx, pdf_dict *info_dict)
for (i=0;i<5;i++)
{
- if (pdfi_dict_knownget(ctx, info_dict, KeyNames[i], &o))
+ if (pdfi_dict_knownget(ctx, info_dict, KeyNames[i], &o) > 0)
{
(void)pdfi_dict_put(ctx, Info, KeyNames[i], (pdf_obj *)o);
pdfi_countdown(o);
}
}
- code = pdfi_mark_from_dict(ctx, Info, NULL, "DOCINFO");
+ code = pdfi_pdfmark_from_dict(ctx, Info, NULL, "DOCINFO");
exit:
pdfi_countdown(Info);
return;
@@ -996,7 +994,7 @@ exit:
* to adjust the various Box entries (note this routine must be called
* early!).
*/
-void pdfi_write_boxes_pdfmark(pdf_context *ctx, pdf_dict *page_dict)
+void pdfi_pdfmark_write_boxes(pdf_context *ctx, pdf_dict *page_dict)
{
int i, code = 0;
pdf_dict *BoxDict = NULL;
@@ -1040,7 +1038,7 @@ void pdfi_write_boxes_pdfmark(pdf_context *ctx, pdf_dict *page_dict)
for (i=0;i<4;i++)
{
/* Check each Bos name in turn */
- if (pdfi_dict_knownget(ctx, page_dict, BoxNames[i], &o)){
+ if (pdfi_dict_knownget(ctx, page_dict, BoxNames[i], &o) > 0){
gs_rect box;
pdf_array *new_array = NULL;
@@ -1076,7 +1074,7 @@ void pdfi_write_boxes_pdfmark(pdf_context *ctx, pdf_dict *page_dict)
}
/* Send all the Box entries to the device */
- (void)pdfi_mark_from_dict(ctx, BoxDict, NULL, "PAGE");
+ (void)pdfi_pdfmark_from_dict(ctx, BoxDict, NULL, "PAGE");
exit:
pdfi_countdown(BoxDict);
diff --git a/pdf/pdf_mark.h b/pdf/pdf_mark.h
index b732d190..653eafb7 100644
--- a/pdf/pdf_mark.h
+++ b/pdf/pdf_mark.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -18,15 +18,16 @@
#ifndef PDF_MARK
#define PDF_MARK
-int pdfi_mark_from_dict(pdf_context *ctx, pdf_dict *dict, gs_matrix *ctm, const char *type);
-int pdfi_mark_object(pdf_context *ctx, pdf_obj *object, const char *label);
-int pdfi_mark_modDest(pdf_context *ctx, pdf_dict *dict);
-int pdfi_mark_modA(pdf_context *ctx, pdf_dict *dict);
-int pdfi_mark_stream(pdf_context *ctx, pdf_stream *stream);
-int pdfi_mark_dict(pdf_context *ctx, pdf_dict *dict);
-int pdfi_mark_embed_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec);
-int pdfi_mark_get_objlabel(pdf_context *ctx, pdf_obj *obj, char **label);
-void pdfi_write_boxes_pdfmark(pdf_context *ctx, pdf_dict *page_dict);
-void pdfi_write_docinfo_pdfmark(pdf_context *ctx, pdf_dict *info_dict);
+int pdfi_pdfmark_from_dict(pdf_context *ctx, pdf_dict *dict, gs_matrix *ctm, const char *type);
+int pdfi_pdfmark_from_objarray(pdf_context *ctx, pdf_obj **objarray, int len, gs_matrix *ctm, const char *type);
+int pdfi_pdfmark_object(pdf_context *ctx, pdf_obj *object, const char *label);
+int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *dict);
+int pdfi_pdfmark_modA(pdf_context *ctx, pdf_dict *dict);
+int pdfi_pdfmark_stream(pdf_context *ctx, pdf_stream *stream);
+int pdfi_pdfmark_dict(pdf_context *ctx, pdf_dict *dict);
+int pdfi_pdfmark_embed_filespec(pdf_context *ctx, pdf_string *name, pdf_dict *filespec);
+int pdfi_pdfmark_get_objlabel(pdf_context *ctx, pdf_obj *obj, char **label);
+void pdfi_pdfmark_write_boxes(pdf_context *ctx, pdf_dict *page_dict);
+void pdfi_pdfmark_write_docinfo(pdf_context *ctx, pdf_dict *info_dict);
#endif
diff --git a/pdf/pdf_misc.c b/pdf/pdf_misc.c
index 1240d5bc..11c5dde5 100644
--- a/pdf/pdf_misc.c
+++ b/pdf/pdf_misc.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,8 +18,10 @@
#include "pdf_int.h"
#include "pdf_stack.h"
#include "pdf_misc.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "gspath.h" /* For gs_strokepath() */
+#include "gspaint.h" /* For gs_erasepage() */
#include "gsicc_manage.h" /* For gsicc_get_default_type() */
#include "gsstate.h" /* for gs_setrenderingintent() */
diff --git a/pdf/pdf_obj.c b/pdf/pdf_obj.c
index 931f2137..58bd59b0 100644
--- a/pdf/pdf_obj.c
+++ b/pdf/pdf_obj.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -23,6 +23,7 @@
#include "pdf_deref.h" /* for replace_cache_entry() */
#include "pdf_mark.h"
#include "pdf_file.h" /* for pdfi_stream_to_buffer() */
+#include "pdf_loop_detect.h"
/***********************************************************************************/
/* Functions to create the various kinds of 'PDF objects', Created objects have a */
@@ -49,7 +50,7 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
break;
case PDF_STRING:
case PDF_NAME:
- bytes = sizeof(pdf_string);
+ bytes = sizeof(pdf_string) + size - sizeof(PDF_NAME_DECLARED_LENGTH);
break;
case PDF_ARRAY:
bytes = sizeof(pdf_array);
@@ -64,7 +65,7 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
bytes = sizeof(pdf_bool);
break;
case PDF_KEYWORD:
- bytes = sizeof(pdf_keyword);
+ bytes = sizeof(pdf_keyword) + size - sizeof(PDF_NAME_DECLARED_LENGTH);
break;
/* The following aren't PDF object types, but are objects we either want to
* reference count, or store on the stack.
@@ -99,17 +100,7 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
case PDF_KEYWORD:
case PDF_STRING:
case PDF_NAME:
- {
- unsigned char *data = NULL;
- data = (unsigned char *)gs_alloc_bytes(ctx->memory, size, "pdfi_object_alloc");
- if (data == NULL) {
- gs_free_object(ctx->memory, *obj, "pdfi_object_alloc");
- *obj = NULL;
- return_error(gs_error_VMerror);
- }
- ((pdf_string *)*obj)->data = data;
- ((pdf_string *)*obj)->length = size;
- }
+ ((pdf_string *)*obj)->length = size;
break;
case PDF_ARRAY:
{
@@ -131,23 +122,18 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
break;
case PDF_DICT:
{
- pdf_obj **keys = NULL, **values = NULL;
+ pdf_dict_entry *entries = NULL;
((pdf_dict *)*obj)->size = size;
if (size > 0) {
- keys = (pdf_obj **)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_obj *), "pdfi_object_alloc");
- values = (pdf_obj **)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_obj *), "pdfi_object_alloc");
- if (keys == NULL || values == NULL) {
+ entries = (pdf_dict_entry *)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_dict_entry), "pdfi_object_alloc");
+ if (entries == NULL) {
gs_free_object(ctx->memory, *obj, "pdfi_object_alloc");
- gs_free_object(ctx->memory, keys, "pdfi_object_alloc");
- gs_free_object(ctx->memory, values, "pdfi_object_alloc");
*obj = NULL;
return_error(gs_error_VMerror);
}
- ((pdf_dict *)*obj)->values = values;
- ((pdf_dict *)*obj)->keys = keys;
- memset(((pdf_dict *)*obj)->values, 0x00, size * sizeof(pdf_obj *));
- memset(((pdf_dict *)*obj)->keys, 0x00, size * sizeof(pdf_obj *));
+ ((pdf_dict *)*obj)->list = entries;
+ memset(((pdf_dict *)*obj)->list, 0x00, size * sizeof(pdf_dict_entry));
}
}
break;
@@ -160,7 +146,7 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
break;
}
#if REFCNT_DEBUG
- (*obj)->UID = ctx->UID++;
+ (*obj)->UID = ctx->ref_UID++;
dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", (*obj)->type, (*obj)->UID);
#endif
return 0;
@@ -205,18 +191,13 @@ static void pdfi_free_namestring(pdf_obj *o)
/* Currently names and strings are the same, so a single cast is OK */
pdf_name *n = (pdf_name *)o;
- if (n->data != NULL)
- gs_free_object(OBJ_MEMORY(n), n->data, "pdf interpreter free name or string data");
gs_free_object(OBJ_MEMORY(n), n, "pdf interpreter free name or string");
}
static void pdfi_free_keyword(pdf_obj *o)
{
- /* Currently names and strings are the same, so a single cast is OK */
pdf_keyword *k = (pdf_keyword *)o;
- if (k->data != NULL)
- gs_free_object(OBJ_MEMORY(k), k->data, "pdf interpreter free keyword data");
gs_free_object(OBJ_MEMORY(k), k, "pdf interpreter free keyword");
}
@@ -238,6 +219,8 @@ static void pdfi_free_stream(pdf_obj *o)
void pdfi_free_object(pdf_obj *o)
{
+ if (o == NULL)
+ return;
switch(o->type) {
case PDF_ARRAY_MARK:
case PDF_DICT_MARK:
@@ -540,7 +523,7 @@ static int pdfi_obj_int_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *le
buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_int_str(data)");
if (buf == NULL)
return_error(gs_error_VMerror);
- snprintf(buf, size, "%ld", number->value.i);
+ snprintf(buf, size, "%"PRId64"", number->value.i);
*data = (byte *)buf;
*len = strlen(buf);
return code;
@@ -554,7 +537,7 @@ static int pdfi_obj_getrefstr(pdf_context *ctx, uint64_t object_num, uint32_t ge
buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_getrefstr(data)");
if (buf == NULL)
return_error(gs_error_VMerror);
- snprintf(buf, size, "%ld %d R", object_num, generation);
+ snprintf(buf, size, "%"PRId64" %d R", object_num, generation);
*data = (byte *)buf;
*len = strlen(buf);
return 0;
@@ -573,7 +556,7 @@ static int pdfi_obj_indirect_str(pdf_context *ctx, pdf_obj *obj, byte **data, in
ref->is_highlevelform = false;
} else {
if (!ref->is_marking) {
- code = pdfi_dereference(ctx, ref->ref_object_num, ref->ref_generation_num, &object);
+ code = pdfi_deref_loop_detect(ctx, ref->ref_object_num, ref->ref_generation_num, &object);
if (code == gs_error_undefined) {
/* Do something sensible for undefined reference (this would be a broken file) */
/* TODO: Flag an error? */
@@ -584,10 +567,10 @@ static int pdfi_obj_indirect_str(pdf_context *ctx, pdf_obj *obj, byte **data, in
goto exit;
if (code == 0) {
if (object->type == PDF_STREAM) {
- code = pdfi_mark_stream(ctx, (pdf_stream *)object);
+ code = pdfi_pdfmark_stream(ctx, (pdf_stream *)object);
if (code < 0) goto exit;
} else if (object->type == PDF_DICT) {
- code = pdfi_mark_dict(ctx, (pdf_dict *)object);
+ code = pdfi_pdfmark_dict(ctx, (pdf_dict *)object);
if (code < 0) goto exit;
} else {
code = pdfi_obj_to_string(ctx, object, data, len);
@@ -833,6 +816,10 @@ static int pdfi_obj_dict_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *l
uint64_t index, dictsize;
uint64_t itemnum = 0;
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
code = pdfi_bufstream_init(ctx, &bufstream);
if (code < 0) goto exit;
@@ -851,6 +838,18 @@ static int pdfi_obj_dict_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *l
/* Note: We specifically fetch without dereferencing, so there will be no circular
* references to handle here.
*/
+ /* Wrong.... */
+
+ if (dict->object_num !=0 ) {
+ if (pdfi_loop_detector_check_object(ctx, dict->object_num)) {
+ code = gs_note_error(gs_error_circular_reference);
+ goto exit;
+ }
+ code = pdfi_loop_detector_add_object(ctx, dict->object_num);
+ if (code < 0)
+ goto exit;
+ }
+
/* Get each (key,val) pair from dict and setup param for it */
code = pdfi_dict_key_first(ctx, dict, (pdf_obj **)&Key, &index);
while (code >= 0) {
@@ -914,6 +913,10 @@ static int pdfi_obj_dict_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *l
pdfi_countdown(Key);
pdfi_countdown(Value);
pdfi_bufstream_free(ctx, &bufstream);
+ if (code < 0)
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ else
+ code = pdfi_loop_detector_cleartomark(ctx);
return code;
}
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)
diff --git a/pdf/pdf_optcontent.h b/pdf/pdf_optcontent.h
index aa25b017..375da5d7 100644
--- a/pdf/pdf_optcontent.h
+++ b/pdf/pdf_optcontent.h
@@ -21,6 +21,8 @@ bool pdfi_oc_is_ocg_visible(pdf_context *ctx, pdf_dict *ocdict);
int pdfi_oc_init(pdf_context *ctx);
int pdfi_oc_free(pdf_context *ctx);
bool pdfi_oc_is_off(pdf_context *ctx);
+int pdfi_op_MP(pdf_context *ctx);
+int pdfi_op_DP(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict);
int pdfi_op_BMC(pdf_context *ctx);
int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict);
int pdfi_op_EMC(pdf_context *ctx);
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index 58833076..f2389fea 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.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
@@ -26,6 +26,7 @@
#include "pdf_loop_detect.h"
#include "pdf_colour.h"
#include "pdf_trans.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_misc.h"
#include "pdf_optcontent.h"
@@ -677,72 +678,10 @@ static void release_page_DefaultSpaces(pdf_context *ctx)
static int setup_page_DefaultSpaces(pdf_context *ctx, pdf_dict *page_dict)
{
- int code = 0;
- pdf_dict *resources_dict = NULL, *colorspaces_dict = NULL;
- pdf_obj *DefaultSpace = NULL;
-
/* First off, discard any dangling Default* colour spaces, just in case. */
release_page_DefaultSpaces(ctx);
- if (ctx->args.NOSUBSTDEVICECOLORS)
- return 0;
-
- /* Create any required DefaultGray, DefaultRGB or DefaultCMYK
- * spaces.
- */
- code = pdfi_dict_knownget(ctx, page_dict, "Resources", (pdf_obj **)&resources_dict);
- if (code > 0) {
- code = pdfi_dict_knownget(ctx, resources_dict, "ColorSpace", (pdf_obj **)&colorspaces_dict);
- if (code > 0) {
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultGray", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, page_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space instead, this is as per the spec.
- */
- if (code >= 0) {
- ctx->page.DefaultGray_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultRGB", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, page_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space instead, this is as per the spec.
- */
- if (code >= 0) {
- ctx->page.DefaultRGB_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- code = pdfi_dict_knownget(ctx, colorspaces_dict, "DefaultCMYK", &DefaultSpace);
- if (code > 0) {
- gs_color_space *pcs;
- code = pdfi_create_colorspace(ctx, DefaultSpace, NULL, page_dict, &pcs, false);
- /* If any given Default* space fails simply ignore it, we wil then use the Device
- * space instead, this is as per the spec.
- */
- if (code >= 0) {
- ctx->page.DefaultCMYK_cs = pcs;
- pdfi_set_colour_callback(pcs, ctx, NULL);
- }
- }
- pdfi_countdown(DefaultSpace);
- DefaultSpace = NULL;
- }
- }
-
- pdfi_countdown(DefaultSpace);
- pdfi_countdown(resources_dict);
- pdfi_countdown(colorspaces_dict);
- return 0;
+ return(pdfi_setup_DefaultSpaces(ctx, page_dict));
}
int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
@@ -766,18 +705,18 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
char extra_info[256];
page_dict_error = true;
- gs_sprintf(extra_info, "*** ERROR: Page %ld has invalid Page dict, skipping\n", page_num+1);
+ gs_snprintf(extra_info, sizeof(extra_info), "*** ERROR: Page %ld has invalid Page dict, skipping\n", page_num+1);
pdfi_set_error(ctx, 0, NULL, E_PDF_PAGEDICTERROR, "pdfi_page_render", extra_info);
if (code != gs_error_VMerror && !ctx->args.pdfstoponerror)
code = 0;
- goto exit2;
+ goto exit3;
}
pdfi_device_set_flags(ctx);
code = pdfi_check_page(ctx, page_dict, init_graphics);
if (code < 0)
- goto exit2;
+ goto exit3;
if (ctx->args.pdfdebug) {
dbgmprintf2(ctx->memory, "Current page %ld transparency setting is %d", page_num+1,
@@ -791,7 +730,7 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
code = pdfi_dict_knownget_type(ctx, page_dict, "Group", PDF_DICT, (pdf_obj **)&group_dict);
if (code < 0)
- goto exit2;
+ goto exit3;
if (group_dict != NULL)
page_group_known = true;
@@ -829,7 +768,7 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
}
/* Write the various CropBox, TrimBox etc to the device */
- pdfi_write_boxes_pdfmark(ctx, page_dict);
+ pdfi_pdfmark_write_boxes(ctx, page_dict);
code = setup_page_DefaultSpaces(ctx, page_dict);
if (code < 0)
@@ -866,7 +805,7 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
/* We don't retain the PDF14 device */
code = gs_push_pdf14trans_device(ctx->pgs, false, false, trans_depth, ctx->page.num_spots);
if (code >= 0) {
- if (page_group_known) {
+ if (ctx->page.has_transparency && page_group_known) {
code = pdfi_trans_begin_page_group(ctx, page_dict, group_dict);
/* If setting the page group failed for some reason, abandon the page group,
* but continue with the page
@@ -889,18 +828,19 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
pdfi_set_DefaultQState(ctx, ctx->pgs);
/* Render one page (including annotations) */
+ if (!ctx->args.QUIET)
+ outprintf(ctx->memory, "Page %"PRId64"\n", page_num + 1);
+
code = pdfi_process_one_page(ctx, page_dict);
- if (ctx->page.has_transparency && page_group_known) {
+ if (need_pdf14 && ctx->page.has_transparency && page_group_known) {
code1 = pdfi_trans_end_group(ctx);
}
- pdfi_countdown(ctx->page.CurrentPageDict);
- ctx->page.CurrentPageDict = NULL;
-
if (need_pdf14) {
if (code1 < 0) {
(void)gs_abort_pdf14trans_device(ctx->pgs);
+ code = code1;
goto exit1;
}
@@ -910,10 +850,15 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
}
}
- exit1:
+exit1:
pdfi_free_DefaultQState(ctx);
pdfi_grestore(ctx);
- exit2:
+
+exit2:
+ pdfi_countdown(ctx->page.CurrentPageDict);
+ ctx->page.CurrentPageDict = NULL;
+
+exit3:
pdfi_countdown(page_dict);
pdfi_countdown(group_dict);
diff --git a/pdf/pdf_path.c b/pdf/pdf_path.c
index ef6f1328..a9724def 100644
--- a/pdf/pdf_path.c
+++ b/pdf/pdf_path.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -16,6 +16,7 @@
/* Path operations for the PDF interpreter */
#include "pdf_int.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_path.h"
#include "pdf_stack.h"
@@ -120,22 +121,28 @@ static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
- code = pdfi_gsave(ctx);
- if (code < 0) goto exit;
-
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Fill);
if (code == 0) {
+ /* If we don't gsave/grestore round the fill, then the file
+ * /tests_private/pdf/sumatra/954_-_dashed_lines_hardly_visible.pdf renders
+ * incorrectly. However we must not gsave/grestore round the trans_setup
+ * trans_teardown, because that might set pgs->soft_mask_id and if we restore
+ * back to a point where that is not set then pdfwrite doesn't work properly.
+ */
+ code = pdfi_gsave(ctx);
+ if (code < 0) goto exit;
+
if (use_eofill)
code = gs_eofill(ctx->pgs);
else
code = gs_fill(ctx->pgs);
+ code1 = pdfi_grestore(ctx);
+ if (code == 0) code = code1;
+
code1 = pdfi_trans_teardown(ctx, &state);
if (code == 0) code = code1;
}
- code1 = pdfi_grestore(ctx);
- if (code == 0) code = code1;
-
exit:
code1 = pdfi_newpath(ctx);
if (code == 0) code = code1;
@@ -164,20 +171,27 @@ int pdfi_stroke(pdf_context *ctx)
if (pdfi_oc_is_off(ctx))
goto exit;
- code = pdfi_gsave(ctx);
- if (code < 0) goto exit;
+/* code = pdfi_gsave(ctx);
+ if (code < 0) goto exit;*/
gs_swapcolors_quick(ctx->pgs);
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke);
if (code == 0) {
+ code = pdfi_gsave(ctx);
+ if (code < 0) goto exit;
+
code = gs_stroke(ctx->pgs);
+
+ code1 = pdfi_grestore(ctx);
+ if (code == 0) code = code1;
+
code1 = pdfi_trans_teardown(ctx, &state);
if (code == 0) code = code1;
}
gs_swapcolors_quick(ctx->pgs);
- code1 = pdfi_grestore(ctx);
- if (code == 0) code = code1;
+/* code1 = pdfi_grestore(ctx);
+ if (code == 0) code = code1;*/
exit:
code1 = pdfi_newpath(ctx);
@@ -378,22 +392,23 @@ static int pdfi_B_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
- code = pdfi_gsave(ctx);
- if (code < 0) goto exit;
-
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke);
if (code == 0) {
+ code = pdfi_gsave(ctx);
+ if (code < 0) goto exit;
+
if (use_eofill)
code = gs_eofillstroke(ctx->pgs, &code1);
else
code = gs_fillstroke(ctx->pgs, &code1);
+
+ code1 = pdfi_grestore(ctx);
+ if (code == 0) code = code1;
+
code1 = pdfi_trans_teardown(ctx, &state);
if (code >= 0) code = code1;
}
- code1 = pdfi_grestore(ctx);
- if (code == 0) code = code1;
-
exit:
code1 = pdfi_newpath(ctx);
if (code == 0) code = code1;
diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c
index 9d4f9eaa..57a16449 100644
--- a/pdf/pdf_pattern.c
+++ b/pdf/pdf_pattern.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
@@ -21,6 +21,7 @@
#include "pdf_pattern.h"
#include "pdf_stack.h"
#include "pdf_array.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_file.h"
#include "pdf_dict.h"
@@ -116,8 +117,7 @@ static void pdfi_free_pattern_context(pdf_pattern_context_t *context)
static bool
pdfi_pattern_purge_proc(gx_color_tile * ctile, void *proc_data)
{
- gs_id id = (gs_id)proc_data;
- if (ctile->id == id)
+ if (ctile->id == *((gx_bitmap_id *)proc_data))
return true;
return false;
}
@@ -138,7 +138,7 @@ void pdfi_pattern_cleanup(gs_memory_t * mem, void *p)
context->shading == NULL && context->ctx->pgs->pattern_cache != NULL
&& gx_pattern_cache_get_entry(context->ctx->pgs, pinst->id, &pctile) == 0
&& gx_pattern_tile_is_clist(pctile)) {
- gx_pattern_cache_winnow(gstate_pattern_cache(context->ctx->pgs), pdfi_pattern_purge_proc, (void *)(pctile->id));
+ gx_pattern_cache_winnow(gstate_pattern_cache(context->ctx->pgs), pdfi_pattern_purge_proc, (void *)(&pctile->id));
}
if (context != NULL) {
@@ -240,10 +240,6 @@ pdfi_pattern_paint_high_level(const gs_client_color *pcc, gs_gstate *pgs_ignore)
gx_device_color *pdc = gs_currentdevicecolor_inline(pgs);
pattern_accum_param_s param;
- code = gx_pattern_cache_add_dummy_entry(pgs, pinst, pgs->device->color_info.depth);
- if (code < 0)
- return code;
-
code = pdfi_gsave(ctx);
if (code < 0)
return code;
@@ -293,6 +289,17 @@ pdfi_pattern_paint_high_level(const gs_client_color *pcc, gs_gstate *pgs_ignore)
code = pdfi_grestore(ctx);
if (code < 0)
return code;
+
+ /* We create the dummy cache entry last, after we've executed the Pattern PaintProc. This is because
+ * if we ran another Pattern during the PaintProc, and that pattern has an id which happens to
+ * collide with the id of this pattern, it would overwrite the entry in the pattern cache.
+ * Deferring the entry in the cache until we are complete prevents this happening.
+ * For an example see Bug693422.pdf.
+ */
+ code = gx_pattern_cache_add_dummy_entry(pgs, pinst, pgs->device->color_info.depth);
+ if (code < 0)
+ return code;
+
return gs_error_handled;
errorExit:
@@ -439,6 +446,14 @@ pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_di
if (code < 0)
goto exit;
+ /* The pattern instance holds the pattern step as floats, make sure they
+ * will fit.
+ */
+ if (XStep < -MAX_FLOAT || XStep > MAX_FLOAT || YStep < -MAX_FLOAT || YStep > MAX_FLOAT) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto exit;
+ }
+
/* The spec says Resources are required, but in fact this doesn't seem to be true.
* (tests_private/pdf/sumatra/infinite_pattern_recursion.pdf)
*/
@@ -468,11 +483,15 @@ pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_di
goto exit;
}
- /* See if pattern uses transparency */
- if (ctx->page.has_transparency) {
- code = pdfi_check_Pattern_transparency(ctx, pdict, page_dict, &transparency);
- if (code < 0)
- goto exit;
+ /* See if pattern uses transparency, or if we are in an overprint
+ simulation situation */
+ if (ctx->page.simulate_op)
+ transparency = true;
+ else
+ if (ctx->page.has_transparency) {
+ code = pdfi_check_Pattern_transparency(ctx, pdict, page_dict, &transparency);
+ if (code < 0)
+ goto exit;
}
/* TODO: Resources? Maybe I should check that they are all valid before proceeding, or something? */
@@ -512,7 +531,7 @@ pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_di
if (code < 0)
goto exit;
exit:
- pdfi_countdown(context);
+ gs_free_object(ctx->memory, context, "pdfi_setpattern_type1(context)");
pdfi_countdown(Resources);
pdfi_countdown(Matrix);
pdfi_countdown(BBox);
diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c
index dafcd4c0..2c2badf2 100644
--- a/pdf/pdf_repair.c
+++ b/pdf/pdf_repair.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -52,7 +52,7 @@ static int pdfi_repair_add_object(pdf_context *ctx, uint64_t obj, uint64_t gen,
ctx->xref_table->type = PDF_XREF_TABLE;
ctx->xref_table->xref_size = obj + 1;
#if REFCNT_DEBUG
- ctx->xref_table->UID = ctx->UID++;
+ ctx->xref_table->UID = ctx->ref_UID++;
dmprintf1(ctx->memory, "Allocated xref table with UID %"PRIi64"\n", ctx->xref_table->UID);
#endif
pdfi_countup(ctx->xref_table);
@@ -109,24 +109,24 @@ int pdfi_repair_file(pdf_context *ctx)
*/
pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
{
- char Buffer[10], test[] = "%PDF";
+ static const char test[] = "%PDF";
int index = 0;
do {
- code = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, ctx->main_stream);
- if (code < 0)
+ int c = pdfi_read_byte(ctx, ctx->main_stream);
+ if (c < 0)
goto exit;
- if (Buffer[index] == test[index])
+ if (c == test[index])
index++;
else
index = 0;
- } while (index < 4 && ctx->main_stream->eof == false);
- if (memcmp(Buffer, test, 4) != 0) {
+ } while (index < 4);
+ if (index != 4) {
code = gs_note_error(gs_error_undefined);
goto exit;
}
- pdfi_unread(ctx, ctx->main_stream, (byte *)Buffer, 4);
+ pdfi_unread(ctx, ctx->main_stream, (byte *)test, 4);
pdfi_skip_comment(ctx, ctx->main_stream);
}
if (ctx->main_stream->eof == true) {
@@ -188,7 +188,7 @@ int pdfi_repair_file(pdf_context *ctx)
/* move all the saved offsets up by one */
saved_offset[0] = saved_offset[1];
saved_offset[1] = saved_offset[2];
- saved_offset[2] = pdfi_unread_tell(ctx);;
+ saved_offset[2] = pdfi_unread_tell(ctx);
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
if (code < 0) {
@@ -228,21 +228,22 @@ int pdfi_repair_file(pdf_context *ctx)
break;
} else {
if (k->key == TOKEN_STREAM) {
- char Buffer[10], test[] = "endstream";
+ static const char test[] = "endstream";
int index = 0;
do {
- code = pdfi_read_bytes(ctx, (byte *)&Buffer[index], 1, 1, ctx->main_stream);
- if (code < 0) {
- if (code != gs_error_VMerror && code != gs_error_ioerror)
- continue;
+ int c = pdfi_read_byte(ctx, ctx->main_stream);
+ if (c == EOFC)
+ break;
+ if (c < 0)
goto exit;
- }
- if (Buffer[index] == test[index])
+ if (c == test[index])
index++;
+ else if (c == test[0]) /* Pesky 'e' appears twice */
+ index = 1;
else
index = 0;
- } while (index < 9 && ctx->main_stream->eof == false);
+ } while (index < 9);
do {
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
if (code < 0) {
@@ -250,16 +251,18 @@ int pdfi_repair_file(pdf_context *ctx)
continue;
goto exit;
}
- if (ctx->stack_top[-1]->type == PDF_KEYWORD){
- pdf_keyword *k = (pdf_keyword *)ctx->stack_top[-1];
- if (k->key == TOKEN_ENDOBJ) {
- code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
- if (code < 0) {
- if (code != gs_error_VMerror && code != gs_error_ioerror)
- break;
- goto exit;
+ if (code > 0) {
+ if (ctx->stack_top[-1]->type == PDF_KEYWORD){
+ pdf_keyword *k = (pdf_keyword *)ctx->stack_top[-1];
+ if (k->key == TOKEN_ENDOBJ) {
+ code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
+ if (code < 0) {
+ if (code != gs_error_VMerror && code != gs_error_ioerror)
+ break;
+ goto exit;
+ }
+ break;
}
- break;
}
}
}while(ctx->main_stream->eof == false);
@@ -287,7 +290,7 @@ int pdfi_repair_file(pdf_context *ctx)
} else {
if (k->key == TOKEN_TRAILER) {
code = pdfi_read_bare_object(ctx, ctx->main_stream, 0, 0, 0);
- if (code == 0 && ctx->stack_top[-1]->type == PDF_DICT) {
+ if (code == 0 && pdfi_count_stack(ctx) > 0 && ctx->stack_top[-1]->type == PDF_DICT) {
if (ctx->Trailer) {
pdf_dict *d = (pdf_dict *)ctx->stack_top[-1];
bool known = false;
@@ -420,13 +423,15 @@ int pdfi_repair_file(pdf_context *ctx)
if (code == 0) {
for (j=0;j < N; j++) {
code = pdfi_read_token(ctx, compressed_stream, 0, 0);
- if (code == 0) {
+ if (code == 0)
+ break;
+ if (code > 0) {
o = ctx->stack_top[-1];
if (((pdf_obj *)o)->type == PDF_INT) {
obj_num = ((pdf_num *)o)->value.i;
pdfi_pop(ctx, 1);
code = pdfi_read_token(ctx, compressed_stream, 0, 0);
- if (code == 0) {
+ if (code > 0) {
o = ctx->stack_top[-1];
if (((pdf_obj *)o)->type == PDF_INT) {
offset = ((pdf_num *)o)->value.i;
@@ -436,11 +441,16 @@ int pdfi_repair_file(pdf_context *ctx)
code = gs_note_error(gs_error_rangecheck);
goto exit;
}
- ctx->xref_table->xref[obj_num].compressed = true;
- ctx->xref_table->xref[obj_num].free = false;
- ctx->xref_table->xref[obj_num].object_num = obj_num;
- ctx->xref_table->xref[obj_num].u.compressed.compressed_stream_num = i;
- ctx->xref_table->xref[obj_num].u.compressed.object_index = j;
+ if (obj_num >= ctx->xref_table->xref_size)
+ code = pdfi_repair_add_object(ctx, obj_num, 0, 0);
+
+ if (code >= 0) {
+ ctx->xref_table->xref[obj_num].compressed = true;
+ ctx->xref_table->xref[obj_num].free = false;
+ ctx->xref_table->xref[obj_num].object_num = obj_num;
+ ctx->xref_table->xref[obj_num].u.compressed.compressed_stream_num = i;
+ ctx->xref_table->xref[obj_num].u.compressed.object_index = j;
+ }
}
}
}
diff --git a/pdf/pdf_sec.c b/pdf/pdf_sec.c
index ff608052..fa7131f8 100644
--- a/pdf/pdf_sec.c
+++ b/pdf/pdf_sec.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020-2021 Artifex Software, Inc.
+/* Copyright (C) 2020-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -57,6 +57,7 @@ static int pdf_compute_encryption_key_preR5(pdf_context *ctx, char *Password, in
gs_md5_state_t md5;
pdf_array *a = NULL;
pdf_string *s = NULL;
+ pdf_dict *d = NULL;
*EKey = NULL;
/* Algorithm 3.2 */
@@ -86,7 +87,11 @@ static int pdf_compute_encryption_key_preR5(pdf_context *ctx, char *Password, in
gs_md5_append(&md5, (gs_md5_byte_t *)P, 4);
/* 5. Pass the first element of the file's file identifier array */
- code = pdfi_dict_get_type(ctx, ctx->Trailer, "ID", PDF_ARRAY, (pdf_obj **)&a);
+ /* See comment in pdfi_read_Root() for details of why we indirect through 'd' */
+ d = ctx->Trailer;
+ pdfi_countup(d);
+ code = pdfi_dict_get_type(ctx, d, "ID", PDF_ARRAY, (pdf_obj **)&a);
+ pdfi_countdown(d);
if (code < 0) {
if (code == gs_error_undefined) {
emprintf(ctx->memory, "\n **** Error: ID key in the trailer is required for encrypted files.\n");
@@ -430,6 +435,7 @@ static int check_user_password_preR5(pdf_context *ctx, char *Password, int Len,
gs_md5_state_t md5;
pdf_string *s = NULL;
pdf_array *a = NULL;
+ pdf_dict *d = NULL;
/* Algorithm 3.6, step 1
* perform all but the last step of Algorithm 3,4 (Revision 2)
@@ -482,7 +488,11 @@ static int check_user_password_preR5(pdf_context *ctx, char *Password, int Len,
* Pass the 32 byte padding string from step 1 of Algorithm 3.2 to an MD5 hash */
gs_md5_init(&md5);
gs_md5_append(&md5, (gs_md5_byte_t *)PadString, 32);
- code = pdfi_dict_get_type(ctx, ctx->Trailer, "ID", PDF_ARRAY, (pdf_obj **)&a);
+ /* See comment in pdfi_read_Root() for details of why we indirect through 'd' */
+ d = ctx->Trailer;
+ pdfi_countup(d);
+ code = pdfi_dict_get_type(ctx, d, "ID", PDF_ARRAY, (pdf_obj **)&a);
+ pdfi_countdown(d);
if (code < 0) {
if (code == gs_error_undefined) {
emprintf(ctx->memory, "\n **** Error: ID key in the trailer is required for encrypted files.\n");
@@ -918,6 +928,9 @@ int pdfi_decrypt_string(pdf_context *ctx, pdf_string *string)
pdf_string *EKey = NULL;
char *Buffer = NULL;
+ if (ctx->encryption.StrF == CRYPT_IDENTITY)
+ return 0;
+
if (!is_compressed_object(ctx, string->indirect_num, string->indirect_gen)) {
Buffer = (char *)gs_alloc_bytes(ctx->memory, string->length, "pdfi_decrypt_string");
if (Buffer == NULL)
@@ -978,7 +991,7 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
{
int code = 0;
pdf_dict *CF_dict = NULL, *StdCF_dict = NULL;
- pdf_dict *d = NULL;
+ pdf_dict *d = NULL, *d1 = NULL;
pdf_obj *o = NULL;
pdf_string *s = NULL;
int64_t i64;
@@ -987,7 +1000,12 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "%% Checking for Encrypt dictionary\n");
- code = pdfi_dict_get(ctx, ctx->Trailer, "Encrypt", (pdf_obj **)&d);
+ /* See comment in pdfi_read_Root() for details of why we indirect through 'd' */
+ d1 = ctx->Trailer;
+ pdfi_countup(d1);
+ code = pdfi_dict_get(ctx, d1, "Encrypt", (pdf_obj **)&d);
+ pdfi_countdown(d1);
+ d1 = NULL;
/* Undefined is acceptable here, it just means the PDF file is not ostensibly encrypted */
/* NB pdfi_process_pdf_file() always checks for the Encrypt dictionary before we
@@ -1122,6 +1140,10 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
code = pdfi_dict_knownget_type(ctx, d, "StrF", PDF_NAME, &o);
if (code < 0)
goto done;
+ if (code == 0) {
+ code = gs_note_error(gs_error_undefined);
+ goto done;
+ }
if (!pdfi_name_is((pdf_name *)o, "StdCF")) {
if (pdfi_name_is((pdf_name *)o, "Identity")) {
ctx->encryption.StrF = CRYPT_IDENTITY;
@@ -1236,6 +1258,8 @@ static int check_password_R5(pdf_context *ctx, char *Password, int PasswordLen,
int code;
if (PasswordLen != 0) {
+ pdf_string *P = NULL, *P_UTF8 = NULL;
+
code = check_user_password_R5(ctx, Password, PasswordLen, KeyLen);
if (code >= 0)
return 0;
@@ -1247,33 +1271,28 @@ static int check_password_R5(pdf_context *ctx, char *Password, int PasswordLen,
/* If the supplied Password fails as the user *and* owner password, maybe its in
* the locale, not UTF-8, try converting to UTF-8
*/
+ code = pdfi_object_alloc(ctx, PDF_STRING, strlen(ctx->encryption.Password), (pdf_obj **)&P);
+ if (code < 0)
+ return code;
+ memcpy(P->data, Password, PasswordLen);
+ pdfi_countup(P);
+ code = locale_to_utf8(ctx, P, &P_UTF8);
if (code < 0) {
- pdf_string *P = NULL, *P_UTF8 = NULL;
-
- code = pdfi_object_alloc(ctx, PDF_STRING, strlen(ctx->encryption.Password), (pdf_obj **)&P);
- if (code < 0) {
- return code;
- }
- memcpy(P->data, Password, PasswordLen);
- pdfi_countup(P);
- code = locale_to_utf8(ctx, P, &P_UTF8);
- if (code < 0) {
- pdfi_countdown(P);
- return code;
- }
- code = check_user_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
- if (code >= 0) {
- pdfi_countdown(P);
- pdfi_countdown(P_UTF8);
- return code;
- }
-
- code = check_owner_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ pdfi_countdown(P);
+ return code;
+ }
+ code = check_user_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ if (code >= 0) {
pdfi_countdown(P);
pdfi_countdown(P_UTF8);
- if (code >= 0)
- return code;
+ return code;
}
+
+ code = check_owner_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ pdfi_countdown(P);
+ pdfi_countdown(P_UTF8);
+ if (code >= 0)
+ return code;
}
code = check_user_password_R5(ctx, (char *)"", 0, KeyLen);
if (code >= 0)
@@ -1287,6 +1306,8 @@ static int check_password_R6(pdf_context *ctx, char *Password, int PasswordLen,
int code;
if (PasswordLen != 0) {
+ pdf_string *P = NULL, *P_UTF8 = NULL;
+
code = check_user_password_R6(ctx, Password, PasswordLen, KeyLen);
if (code >= 0)
return 0;
@@ -1297,32 +1318,28 @@ static int check_password_R6(pdf_context *ctx, char *Password, int PasswordLen,
/* If the supplied Password fails as the user *and* owner password, maybe its in
* the locale, not UTF-8, try converting to UTF-8
*/
+ code = pdfi_object_alloc(ctx, PDF_STRING, strlen(ctx->encryption.Password), (pdf_obj **)&P);
+ if (code < 0)
+ return code;
+ memcpy(P->data, Password, PasswordLen);
+ pdfi_countup(P);
+ code = locale_to_utf8(ctx, P, &P_UTF8);
if (code < 0) {
- pdf_string *P = NULL, *P_UTF8 = NULL;
-
- code = pdfi_object_alloc(ctx, PDF_STRING, strlen(ctx->encryption.Password), (pdf_obj **)&P);
- if (code < 0)
- return code;
- memcpy(P->data, Password, PasswordLen);
- pdfi_countup(P);
- code = locale_to_utf8(ctx, P, &P_UTF8);
- if (code < 0) {
- pdfi_countdown(P);
- return code;
- }
- code = check_user_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
- if (code >= 0) {
- pdfi_countdown(P);
- pdfi_countdown(P_UTF8);
- return code;
- }
-
- code = check_owner_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ pdfi_countdown(P);
+ return code;
+ }
+ code = check_user_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ if (code >= 0) {
pdfi_countdown(P);
pdfi_countdown(P_UTF8);
- if (code >= 0)
- return code;
+ return code;
}
+
+ code = check_owner_password_R5(ctx, (char *)P_UTF8->data, P_UTF8->length, KeyLen);
+ pdfi_countdown(P);
+ pdfi_countdown(P_UTF8);
+ if (code >= 0)
+ return code;
}
code = check_user_password_R6(ctx, (char *)"", 0, KeyLen);
if (code >= 0)
@@ -1352,6 +1369,10 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
case 2:
/* Set up the defaults if not already set */
/* Revision 2 is always 40-bit RC4 */
+ if (KeyLen != 0 && (KeyLen < 40 || KeyLen > 128 || KeyLen % 8 != 0)) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
+ return_error(gs_error_rangecheck);
+ }
if (KeyLen == 0)
KeyLen = 40;
if (ctx->encryption.StmF == CRYPT_NONE)
@@ -1363,8 +1384,9 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
case 3:
/* Set up the defaults if not already set */
/* Revision 3 is always 128-bit RC4 */
- if (KeyLen == 0)
- KeyLen = 128;
+ if (KeyLen != 0 && KeyLen != 128)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
+ KeyLen = 128;
if (ctx->encryption.StmF == CRYPT_NONE)
ctx->encryption.StmF = CRYPT_V2;
if (ctx->encryption.StrF == CRYPT_NONE)
@@ -1372,16 +1394,20 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
code = check_password_preR5(ctx, ctx->encryption.Password, ctx->encryption.PasswordLen, KeyLen, 3);
break;
case 4:
- /* Revision 4 is either AES or RC4, but its always 128-bits */
- if (KeyLen == 0)
+ if (ctx->encryption.StrF != CRYPT_IDENTITY || ctx->encryption.StmF != CRYPT_IDENTITY) {
+ /* Revision 4 is either AES or RC4, but its always 128-bits */
+ if (KeyLen != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
KeyLen = 128;
- /* We can't set the encryption filter, so we have to hope the PDF file did */
- code = check_password_preR5(ctx, ctx->encryption.Password, ctx->encryption.PasswordLen, KeyLen, 4);
+ /* We can't set the encryption filter, so we have to hope the PDF file did */
+ code = check_password_preR5(ctx, ctx->encryption.Password, ctx->encryption.PasswordLen, KeyLen, 4);
+ }
break;
case 5:
/* Set up the defaults if not already set */
- if (KeyLen == 0)
- KeyLen = 256;
+ if (KeyLen != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
+ KeyLen = 256;
if (ctx->encryption.StmF == CRYPT_NONE)
ctx->encryption.StmF = CRYPT_AESV2;
if (ctx->encryption.StrF == CRYPT_NONE)
@@ -1391,8 +1417,9 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
case 6:
/* Set up the defaults if not already set */
/* Revision 6 is always 256-bit AES */
- if (KeyLen == 0)
- KeyLen = 256;
+ if (KeyLen != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
+ KeyLen = 256;
if (ctx->encryption.StmF == CRYPT_NONE)
ctx->encryption.StmF = CRYPT_AESV3;
if (ctx->encryption.StrF == CRYPT_NONE)
diff --git a/pdf/pdf_shading.c b/pdf/pdf_shading.c
index 01a2d0e1..c4e93e88 100644
--- a/pdf/pdf_shading.c
+++ b/pdf/pdf_shading.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -17,6 +17,7 @@
#include "pdf_int.h"
#include "pdf_stack.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_shading.h"
#include "pdf_dict.h"
@@ -35,6 +36,7 @@
#include "gsptype2.h"
#include "gsfunc0.h" /* For gs_function */
#include "gscolor3.h" /* For gs_shfill() */
+#include "gsstate.h" /* For gs_setoverprintmode */
static int pdfi_build_shading_function(pdf_context *ctx, gs_function_t **ppfn, const float *shading_domain, int num_inputs, pdf_dict *shading_dict, pdf_dict *page_dict)
{
@@ -705,8 +707,7 @@ pdfi_shading_build(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
goto shading_error;
pdfi_countdown(cspace);
- if (code >= 0)
- *ppsh = psh;
+ *ppsh = psh;
return code;
shading_error:
@@ -810,7 +811,7 @@ pdfi_shading_setup_trans(pdf_context *ctx, pdfi_trans_state_t *state, pdf_obj *S
/* If we didn't get a BBox for the shading, then we need to create one, in order to
* pass it to the transparency setup, which (potentially, at least, uses it to set
* up a transparency group.
- * In the basence of anything better, we take the currnet clip, turn that into a path
+ * In the absence of anything better, we take the current clip, turn that into a path
* and then get the bounding box of that path. Obviously we don't want to disturb the
* current path in the graphics state, so we do a gsave/grestore round it.
*/
@@ -852,6 +853,7 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
gs_shading_t *psh = NULL;
gs_offset_t savedoffset;
pdfi_trans_state_t trans_state;
+ int trans_required;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
@@ -889,11 +891,18 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
if (code < 0)
goto exit2;
+ /* Shadings fills can't use overprint mode */
+ code = gs_setoverprintmode(ctx->pgs, 0);
+ if (code < 0)
+ goto exit2;
+
code = pdfi_shading_build(ctx, stream_dict, page_dict, Shading, &psh);
if (code < 0)
goto exit2;
- if (ctx->page.has_transparency) {
+ trans_required = pdfi_trans_required(ctx);
+
+ if (trans_required) {
code = pdfi_shading_setup_trans(ctx, &trans_state, Shading);
if (code < 0)
goto exit2;
@@ -905,7 +914,7 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
code = 0;
}
- if (ctx->page.has_transparency) {
+ if (trans_required) {
code1 = pdfi_trans_teardown(ctx, &trans_state);
if (code == 0)
code = code1;
diff --git a/pdf/pdf_text.c b/pdf/pdf_text.c
index 4bc6d907..e6345d0f 100644
--- a/pdf/pdf_text.c
+++ b/pdf/pdf_text.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -21,9 +21,9 @@
#include "pdf_image.h"
#include "pdf_colour.h"
#include "pdf_stack.h"
-#include "pdf_gstate.h"
#include "pdf_font.h"
#include "pdf_font_types.h"
+#include "pdf_gstate.h"
#include "pdf_trans.h"
#include "pdf_optcontent.h"
@@ -486,6 +486,11 @@ static int pdfi_show_set_params(pdf_context *ctx, pdf_string *s, gs_text_params_
}
text->size = s->length;
}
+ else {
+ code = gs_note_error(gs_error_invalidfont);
+ goto text_params_error;
+ }
+
return 0;
text_params_error:
@@ -1081,6 +1086,13 @@ int pdfi_Tj(pdf_context *ctx)
if (s->type != PDF_STRING)
return_error(gs_error_typecheck);
+ /* We can't rely on the stack reference because an error during
+ the text operation (i.e. retrieving objects for glyph metrics
+ may cause the stack to be cleared.
+ */
+ pdfi_countup(s);
+ pdfi_pop(ctx, 1);
+
/* Save the CTM for later restoration */
saved = ctm_only(ctx->pgs);
gs_currentpoint(ctx->pgs, &initial_point);
@@ -1155,7 +1167,7 @@ Tj_error:
ctx->pgs->line_params.half_width = linewidth;
exit:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(s);
return code;
}
@@ -1190,6 +1202,8 @@ int pdfi_TJ(pdf_context *ctx)
pdfi_pop(ctx, 1);
return gs_note_error(gs_error_typecheck);
}
+ pdfi_countup(a);
+ pdfi_pop(ctx, 1);
/* Save the CTM for later restoration */
saved = ctm_only(ctx->pgs);
@@ -1301,7 +1315,7 @@ TJ_error:
ctx->pgs->line_params.half_width = linewidth;
exit:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(a);
return code;
}
@@ -1449,9 +1463,13 @@ int pdfi_Tr(pdf_context *ctx)
* accumulated text to a clip, then set the text rendering mode
* to the non-clip mode, and perform an implicit BT.
*/
- pdfi_ET(ctx);
+ code = pdfi_ET(ctx);
+ if (code < 0)
+ return code;
gs_settextrenderingmode(ctx->pgs, mode);
- pdfi_BT(ctx);
+ code = pdfi_BT(ctx);
+ if (code < 0)
+ return code;
}
else
gs_settextrenderingmode(ctx->pgs, mode);
diff --git a/pdf/pdf_trans.c b/pdf/pdf_trans.c
index 93ab8a6c..df0194d7 100644
--- a/pdf/pdf_trans.c
+++ b/pdf/pdf_trans.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
@@ -20,6 +20,7 @@
#include "pdf_trans.h"
#include "pdf_dict.h"
#include "pdf_colour.h"
+#include "pdf_font_types.h"
#include "pdf_gstate.h"
#include "pdf_array.h"
#include "pdf_image.h"
@@ -32,6 +33,7 @@
#include "gscoord.h" /* For gs_setmatrix()*/
#include "gsstate.h" /* For gs_currentstrokeoverprint() and others */
#include "gspath.h" /* For gs_clippath() */
+#include "gsicc_cache.h" /* For gsicc_profiles_equal() */
/* Implement the TransferFunction using a Function. */
static int
@@ -156,13 +158,15 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
code = pdfi_dict_knownget_type(ctx, SMask, "S", PDF_NAME, (pdf_obj **)&S);
if (code <= 0) {
dmprintf(ctx->memory, "WARNING: Missing 'S' in SMask (defaulting to Luminosity)\n");
+ subtype = TRANSPARENCY_MASK_Luminosity;
}
- if (pdfi_name_is(S, "Luminosity")) {
+ else if (pdfi_name_is(S, "Luminosity")) {
subtype = TRANSPARENCY_MASK_Luminosity;
} else if (pdfi_name_is(S, "Alpha")) {
subtype = TRANSPARENCY_MASK_Alpha;
} else {
dmprintf(ctx->memory, "WARNING: Unknown subtype 'S' in SMask (defaulting to Luminosity)\n");
+ subtype = TRANSPARENCY_MASK_Luminosity;
}
/* TR is transfer function (Optional) */
@@ -172,6 +176,11 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
code = pdfi_build_function(ctx, &gsfunc, NULL, 1, TR, NULL);
if (code < 0)
goto exit;
+ if (gsfunc->params.m != 1 || gsfunc->params.n != 1) {
+ pdfi_free_function(ctx, gsfunc);
+ gsfunc = NULL;
+ dmprintf(ctx->memory, "WARNING: Ignoring invalid TR (number of inpuits or outputs not 1) in SMask\n");
+ }
} else if (TR->type == PDF_NAME) {
if (!pdfi_name_is((pdf_name *)TR, "Identity")) {
dmprintf(ctx->memory, "WARNING: Unknown TR in SMask\n");
@@ -401,6 +410,32 @@ static int pdfi_transparency_group_common(pdf_context *ctx, pdf_dict *page_dict,
return pdfi_gs_begin_transparency_group(ctx->pgs, &params, (const gs_rect *)bbox, group_type);
}
+static bool pdfi_outputprofile_matches_oiprofile(pdf_context *ctx)
+{
+ cmm_dev_profile_t *profile_struct;
+ int code;
+ int k;
+
+ code = dev_proc(ctx->pgs->device, get_profile)(ctx->pgs->device, &profile_struct);
+ if (code < 0)
+ return true; /* Assume they match by default and in error condition */
+
+ if (profile_struct->oi_profile == NULL)
+ return true; /* no OI profile so no special case to worry about */
+ else {
+ /* Check the device profile(s). If any of them do not match, then
+ we assume there is not a match and it may be necessary to
+ use the pdf14 device to prerender to the OI profile */
+ for (k = 0; k < NUM_DEVICE_PROFILES; k++) {
+ if (profile_struct->device_profile[k] != NULL) {
+ if (!gsicc_profiles_equal(profile_struct->oi_profile, profile_struct->device_profile[k]))
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
/* Begin a simple group
* pathbbox -- bbox to use, but can be NULL
*/
@@ -591,14 +626,19 @@ void pdfi_trans_set_needs_OP(pdf_context *ctx)
ctx->page.needs_OP = false;
ctx->page.simulate_op = false;
- switch(ctx->args.overprint_control) {
- case PDF_OVERPRINT_DISABLE:
+ switch(ctx->pgs->device->icc_struct->overprint_control) {
+ case gs_overprint_control_disable:
/* Use defaults */
break;
- case PDF_OVERPRINT_SIMULATE:
+ case gs_overprint_control_simulate:
if (!device_transparency && ctx->page.has_OP) {
if (is_cmyk) {
- if (ctx->page.num_spots > 0) {
+ /* If the page has spots and the device is not spot capable OR
+ if the output intent profile is to be used, but we have
+ a device output profile that is different, then we will be
+ doing simulation with the pdf14 device buffer */
+ if ((ctx->page.num_spots > 0 && !ctx->device_state.spot_capable) ||
+ !pdfi_outputprofile_matches_oiprofile(ctx)) {
ctx->page.needs_OP = true;
ctx->page.simulate_op = true;
}
@@ -608,7 +648,7 @@ void pdfi_trans_set_needs_OP(pdf_context *ctx)
}
}
break;
- case PDF_OVERPRINT_ENABLE:
+ case gs_overprint_control_enable:
default:
if (!is_cmyk || device_transparency)
ctx->page.needs_OP = false;
@@ -624,7 +664,7 @@ void pdfi_trans_set_needs_OP(pdf_context *ctx)
}
/* Figures out if current colorspace is okay for Overprint (see pdf_ops.ps/okOPcs and setupOPtrans) */
-static bool pdfi_trans_okOPcs(pdf_context *ctx)
+bool pdfi_trans_okOPcs(pdf_context *ctx)
{
gs_color_space_index csi;
@@ -707,11 +747,22 @@ int pdfi_trans_setup(pdf_context *ctx, pdfi_trans_state_t *state, gs_rect *bbox,
/* TODO: error handling... */
if (need_group) {
+ bool isolated = false;
+ mode = gs_currentblendmode(ctx->pgs);
+
stroked_bbox = (caller == TRANSPARENCY_Caller_Stroke || caller == TRANSPARENCY_Caller_FillStroke);
+
/* When changing to compatible overprint bm, the group pushed must be non-isolated. The exception
- is if we have a softmask. See /setupOPtrans in pdf_ops.ps */
- code = pdfi_trans_begin_simple_group(ctx, bbox, stroked_bbox, igs->SMask != NULL, false);
- state->GroupPushed = true;
+ is if we have a softmask AND the blend mode is not normal and not compatible.
+ See /setupOPtrans in pdf_ops.ps */
+ if (igs->SMask != NULL && mode != BLEND_MODE_Normal && mode != BLEND_MODE_Compatible)
+ isolated = true;
+ code = pdfi_trans_begin_simple_group(ctx, bbox, stroked_bbox, isolated, false);
+
+ /* Group was not pushed if error */
+ if (code >= 0)
+ state->GroupPushed = true;
+
state->saveStrokeAlpha = gs_getstrokeconstantalpha(ctx->pgs);
state->saveFillAlpha = gs_getfillconstantalpha(ctx->pgs);
code = gs_setfillconstantalpha(ctx->pgs, 1.0);
@@ -725,12 +776,33 @@ int pdfi_trans_setup(pdf_context *ctx, pdfi_trans_state_t *state, gs_rect *bbox,
return code;
}
+int pdfi_trans_required(pdf_context *ctx)
+{
+ gs_blend_mode_t mode;
+
+ if (!ctx->page.has_transparency)
+ return 0;
+
+ mode = gs_currentblendmode(ctx->pgs);
+ if ((mode == BLEND_MODE_Normal || mode == BLEND_MODE_Compatible) &&
+ ctx->pgs->fillconstantalpha == 1 &&
+ ctx->pgs->strokeconstantalpha == 1 &&
+ ((pdfi_int_gstate *)ctx->pgs->client_data)->SMask == NULL)
+ return 0;
+
+ return 1;
+}
+
int pdfi_trans_setup_text(pdf_context *ctx, pdfi_trans_state_t *state, bool is_show)
{
- int Trmode = gs_currenttextrenderingmode(ctx->pgs);
+ int Trmode;
int code, code1;
gs_rect bbox;
+ if (!pdfi_trans_required(ctx))
+ return 0;
+
+ Trmode = gs_currenttextrenderingmode(ctx->pgs);
code = gs_gsave(ctx->pgs);
if (code < 0) goto exit;
@@ -766,11 +838,10 @@ int pdfi_trans_setup_text(pdf_context *ctx, pdfi_trans_state_t *state, bool is_s
int pdfi_trans_teardown_text(pdf_context *ctx, pdfi_trans_state_t *state)
{
- int code = 0;
+ if (!pdfi_trans_required(ctx))
+ return 0;
- code = pdfi_trans_teardown(ctx, state);
-
- return code;
+ return pdfi_trans_teardown(ctx, state);
}
int pdfi_trans_teardown(pdf_context *ctx, pdfi_trans_state_t *state)
diff --git a/pdf/pdf_trans.h b/pdf/pdf_trans.h
index e0057b74..3b71001d 100644
--- a/pdf/pdf_trans.h
+++ b/pdf/pdf_trans.h
@@ -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
@@ -33,6 +33,8 @@ typedef enum {
TRANSPARENCY_Caller_FillStroke /* Also includes EOFillStroke */
} pdfi_transparency_caller_t;
+bool pdfi_trans_okOPcs(pdf_context* ctx);
+int pdfi_trans_required(pdf_context *ctx);
int pdfi_trans_setup_text(pdf_context *ctx, pdfi_trans_state_t *state, bool is_show);
int pdfi_trans_teardown_text(pdf_context *ctx, pdfi_trans_state_t *state);
int pdfi_trans_setup(pdf_context *ctx, pdfi_trans_state_t *state, gs_rect *bbox, pdfi_transparency_caller_t caller);
diff --git a/pdf/pdf_types.h b/pdf/pdf_types.h
index 9b4a9519..b8213e0b 100644
--- a/pdf/pdf_types.h
+++ b/pdf/pdf_types.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -56,7 +56,13 @@ typedef enum pdf_obj_type_e {
PDF_ARRAY_MARK = '[',
PDF_DICT_MARK = '<',
PDF_PROC_MARK = '{',
- PDF_CMAP = 'C'
+ PDF_CMAP = 'C',
+ /* Lastly, for the benefit of duplicate colour space identification, we store either
+ * a name for a colour space, or if there is no name, the context (we can get the
+ * context from the name object if there is one). We need to be able to tell if a
+ * pdf_obj is a name or a context.
+ */
+ PDF_CTX = 'c'
} pdf_obj_type;
#if REFCNT_DEBUG
@@ -103,6 +109,8 @@ typedef enum pdf_obj_type_e {
uint16_t indirect_gen
#endif
+#define PDF_NAME_DECLARED_LENGTH 4096
+
typedef struct pdf_obj_s {
pdf_obj_common;
} pdf_obj;
@@ -124,13 +132,13 @@ typedef struct pdf_num_s {
typedef struct pdf_string_s {
pdf_obj_common;
uint32_t length;
- unsigned char *data;
+ unsigned char data[PDF_NAME_DECLARED_LENGTH];
} pdf_string;
typedef struct pdf_name_s {
pdf_obj_common;
uint32_t length;
- unsigned char *data;
+ unsigned char data[PDF_NAME_DECLARED_LENGTH];
} pdf_name;
typedef enum pdf_key_e {
@@ -143,13 +151,13 @@ typedef enum pdf_key_e {
TOKEN_STARTXREF,
TOKEN_TRAILER,
TOKEN_INVALID_KEY,
-}pdf_key;
+} pdf_key;
typedef struct pdf_keyword_s {
pdf_obj_common;
uint32_t length;
- unsigned char *data;
pdf_key key;
+ unsigned char data[PDF_NAME_DECLARED_LENGTH];
} pdf_keyword;
typedef struct pdf_array_s {
@@ -158,13 +166,18 @@ typedef struct pdf_array_s {
pdf_obj **values;
} pdf_array;
+typedef struct pdf_dict_entry_s {
+ pdf_obj *key;
+ pdf_obj *value;
+} pdf_dict_entry;
+
typedef struct pdf_dict_s {
pdf_obj_common;
uint64_t size;
uint64_t entries;
- pdf_obj **keys;
- pdf_obj **values;
- bool dict_written; /* Has dict been written (for pdfwrite) */
+ pdf_dict_entry *list;
+ bool dict_written; /* Has dict been written (for pdfwrite) */
+ bool is_sorted; /* true if the dictionary has been sorted by Key, for faster searching */
} pdf_dict;
typedef struct pdf_stream_s {
diff --git a/pdf/pdf_warnings.h b/pdf/pdf_warnings.h
new file mode 100644
index 00000000..21b2403f
--- /dev/null
+++ b/pdf/pdf_warnings.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2022 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+#ifndef PARAM
+#define PARAM(A,B) A
+#endif
+PARAM(W_PDF_NOWARNING, "no warning"),
+PARAM(W_PDF_BAD_XREF_SIZE, "incorrect xref size"),
+PARAM(W_PDF_BAD_INLINEFILTER, "used inline filter name inappropriately"),
+PARAM(W_PDF_BAD_INLINECOLORSPACE, "used inline colour space inappropriately"),
+PARAM(W_PDF_BAD_INLINEIMAGEKEY, "used inline image key inappropriately"),
+PARAM(W_PDF_IMAGE_ERROR, "recoverable image error"),
+PARAM(W_PDF_BAD_IMAGEDICT, "recoverable error in image dictionary"),
+PARAM(W_PDF_TOOMANYQ, "encountered more Q than q"),
+PARAM(W_PDF_TOOMANYq, "encountered more q than Q"),
+PARAM(W_PDF_STACKGARBAGE, "garbage left on stack"),
+PARAM(W_PDF_STACKUNDERFLOW, "stack underflow"),
+PARAM(W_PDF_GROUPERROR, "error in group definition"),
+PARAM(W_PDF_OPINVALIDINTEXT, "invalid operator used in text block"),
+PARAM(W_PDF_NOTINCHARPROC, "used invalid operator in CharProc"),
+PARAM(W_PDF_NESTEDTEXTBLOCK, "BT found inside a text block"),
+PARAM(W_PDF_ETNOTEXTBLOCK, "ET found outside text block"),
+PARAM(W_PDF_TEXTOPNOBT, "text operator outside text block"),
+PARAM(W_PDF_DEGENERATETM, "degenerate text matrix"),
+PARAM(W_PDF_BADICC_USE_ALT, "bad ICC colour profile, using alternate"),
+PARAM(W_PDF_BADICC_USECOMPS, "bad ICC vs number components, using components"),
+PARAM(W_PDF_BADTRSWITCH, "bad value for text rendering mode"),
+PARAM(W_PDF_BADSHADING, "error in shading"),
+PARAM(W_PDF_BADPATTERN, "error in pattern"),
+PARAM(W_PDF_NONSTANDARD_OP, "non standard operator found - ignoring"),
+PARAM(W_PDF_NUM_EXPONENT, "number uses illegal exponent form"),
+PARAM(W_PDF_STREAM_HAS_CONTENTS, "Stream has inappropriate /Contents entry"),
+PARAM(W_PDF_STREAM_BAD_DECODEPARMS, "bad DecodeParms"),
+PARAM(W_PDF_MASK_ERROR, "error in Mask"),
+PARAM(W_PDF_ANNOT_AP_ERROR, "error in annotation Appearance"),
+PARAM(W_PDF_BAD_NAME_ESCAPE, "badly escaped name"),
+PARAM(W_PDF_TYPECHECK, "typecheck error"),
+PARAM(W_PDF_BAD_TRAILER, "bad trailer dictionary"),
+PARAM(W_PDF_ANNOT_ERROR, "error in annotation"),
+PARAM(W_PDF_BAD_ICC_PROFILE_LINK, "failed to create ICC profile link"),
+PARAM(W_PDF_OVERFLOW_REAL, "overflowed a real reading a number, assuming 0"),
+PARAM(W_PDF_INVALID_REAL, "failed to read a valid number, assuming 0"),
+PARAM(W_PDF_DEVICEN_USES_ALL, "A DeviceN space used the /All ink name."),
+PARAM(W_PDF_BAD_MEDIABOX, "Couldn't retrieve MediaBox for page, using current media size"),
+PARAM(W_PDF_CA_OUTOFRANGE, "CA or ca value not in range 0.0 to 1.0, clamped to range."),
+PARAM(W_PDF_INVALID_DEFAULTSPACE, "Invalid DefaultGray, DefaultRGB or DefaultCMYK space specified, ignored."),
+PARAM(W_PDF_INVALID_DECRYPT_LEN, "Invalid /Length supplied in Encryption dictionary."),
+PARAM(W_PDF_INVALID_FONT_BASEENC, "Ignoring invalid BaseEncoding name in font"),
+
+#undef PARAM
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index 27c1501e..7e611130 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -175,8 +175,10 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
code = pdfi_dict_get_int(ctx, sdict, "Size", &size);
if (code < 0)
return code;
+ if (size < 1)
+ return 0;
- if (size < 0)
+ if (size < 0 || size > floor((double)ARCH_MAX_SIZE_T / (double)sizeof(xref_entry)))
return_error(gs_error_rangecheck);
/* If this is the first xref stream then allocate the xref table and store the trailer */
@@ -197,7 +199,7 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
ctx->xref_table->type = PDF_XREF_TABLE;
ctx->xref_table->xref_size = size;
#if REFCNT_DEBUG
- ctx->xref_table->UID = ctx->UID++;
+ ctx->xref_table->UID = ctx->ref_UID++;
dmprintf1(ctx->memory, "Allocated xref table with UID %"PRIi64"\n", ctx->xref_table->UID);
#endif
pdfi_countup(ctx->xref_table);
@@ -205,6 +207,9 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
ctx->Trailer = sdict;
pdfi_countup(sdict);
} else {
+ if (size > ctx->xref_table->xref_size)
+ return_error(gs_error_rangecheck);
+
code = pdfi_merge_dicts(ctx, ctx->Trailer, sdict);
if (code < 0) {
if (code == gs_error_VMerror || ctx->args.pdfstoponerror)
@@ -321,7 +326,7 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
for (i=0;i < pdfi_array_size(a);i+=2){
code = pdfi_array_get_int(ctx, a, (uint64_t)i, &start);
- if (code < 0) {
+ if (code < 0 || start < 0) {
pdfi_countdown(a);
pdfi_close_file(ctx, XRefStrm);
pdfi_countdown(ctx->xref_table);
@@ -332,7 +337,6 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
code = pdfi_array_get_int(ctx, a, (uint64_t)i+1, &end);
if (code < 0) {
pdfi_countdown(a);
- pdfi_countdown(start);
pdfi_close_file(ctx, XRefStrm);
pdfi_countdown(ctx->xref_table);
ctx->xref_table = NULL;
@@ -390,6 +394,8 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
if (code < 0)
return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD && ((pdf_keyword *)ctx->stack_top[-1])->key == TOKEN_XREF) {
/* Read old-style xref table */
@@ -412,7 +418,7 @@ static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
/* Its an integer, lets try for index gen obj as a XRef stream */
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0)
+ if (code <= 0)
return(pdfi_repair_file(ctx));
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_INT) {
@@ -426,6 +432,10 @@ static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
pdfi_pop(ctx, 1);
return code;
}
+ if (code == 0) {
+ pdfi_pop(ctx, 1);
+ return_error(gs_error_syntaxerror);
+ }
if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
/* Second element is not an integer, not a valid xref */
@@ -449,10 +459,10 @@ static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
do {
code = pdfi_read_token(ctx, ctx->main_stream, obj_num, gen_num);
- if (code < 0)
+ if (code <= 0)
return pdfi_repair_file(ctx);
- if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD) {
+ if (pdfi_count_stack(ctx) >= 2 && ((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD) {
keyword = (pdf_keyword *)ctx->stack_top[-1];
if (keyword->key == TOKEN_STREAM) {
pdf_dict *dict;
@@ -491,7 +501,7 @@ static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
/* TODO: Not positive this will actually have a length -- just use 0 */
char extra_info[gp_file_name_sizeof];
- gs_sprintf(extra_info, "Xref Stream object %u missing mandatory keyword /Length\n", obj_num);
+ gs_snprintf(extra_info, sizeof(extra_info), "Xref Stream object %u missing mandatory keyword /Length\n", obj_num);
pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAM, "pdfi_read_xref_stream_dict", extra_info);
code = 0;
Length = 0;
@@ -525,36 +535,49 @@ static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
static int skip_to_digit(pdf_context *ctx, pdf_c_stream *s, unsigned int limit)
{
- byte c;
- int bytes, read = 0;
+ int c, read = 0;
do {
- bytes = pdfi_read_bytes(ctx, &c, 1, 1, s);
- if (bytes == 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return_error(gs_error_ioerror);
- if (c >= 0x30 && c <= 0x39) {
- pdfi_unread(ctx, s, &c, 1);
- break;
+ if (c >= '0' && c <= '9') {
+ pdfi_unread_byte(ctx, s, (byte)c);
+ return read;
}
- read += bytes;
- }while (read < limit);
+ read++;
+ } while (read < limit);
+
return read;
}
-static int read_digits(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, unsigned int limit)
+static int read_digits(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, int limit)
{
- int bytes, read = 0;
+ int c, read = 0;
+
+ /* Since the "limit" is a value calculated by the caller,
+ it's easier to check it in one place (here) than before
+ every call.
+ */
+ if (limit <= 0)
+ return_error(gs_error_syntaxerror);
+
+ /* We assume that Buffer always has limit+1 bytes available, so we can
+ * safely terminate it. */
do {
- bytes = pdfi_read_bytes(ctx, &Buffer[read], 1, 1, s);
- if (bytes == 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return_error(gs_error_ioerror);
- if (Buffer[read] < 0x30 || Buffer[read] > 0x39) {
- pdfi_unread(ctx, s, &Buffer[read], 1);
+ if (c < '0' || c > '9') {
+ pdfi_unread_byte(ctx, s, c);
break;
}
- read += bytes;
- }while (read < limit);
+ *Buffer++ = (byte)c;
+ read++;
+ } while (read < limit);
+ *Buffer = 0;
+
return read;
}
@@ -562,9 +585,8 @@ static int read_digits(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, unsigned
static int read_xref_entry_slow(pdf_context *ctx, pdf_c_stream *s, gs_offset_t *offset, uint32_t *generation_num, unsigned char *free)
{
byte Buffer[20];
- int code, read = 0, bytes;
+ int c, code, read = 0;
- memset(Buffer, 0x00, 20);
/* First off, find a number. If we don't find one, and read 20 bytes, throw an error */
code = skip_to_digit(ctx, s, 20);
if (code < 0)
@@ -575,7 +597,6 @@ static int read_xref_entry_slow(pdf_context *ctx, pdf_c_stream *s, gs_offset_t *
code = read_digits(ctx, s, (byte *)&Buffer, (read > 10 ? 20 - read : 10));
if (code < 0)
return code;
- Buffer[code] = 0x00;
read += code;
*offset = atol((const char *)Buffer);
@@ -587,23 +608,22 @@ static int read_xref_entry_slow(pdf_context *ctx, pdf_c_stream *s, gs_offset_t *
read += code;
/* and read it */
- code = read_digits(ctx, s, (byte *)&Buffer, (read > 15 ? 20 - read : 5));
+ code = read_digits(ctx, s, (byte *)&Buffer, (read > 15 ? 20 - read : 5));
if (code < 0)
return code;
- Buffer[code] = 0x00;
read += code;
*generation_num = atol((const char *)Buffer);
do {
- bytes = pdfi_read_bytes(ctx, &Buffer[0], 1, 1, s);
- if (bytes == 0)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
return_error(gs_error_ioerror);
- read += bytes;
- if (Buffer[0] == 0x09 || Buffer[0] == 0x20)
+ read ++;
+ if (c == 0x09 || c == 0x20)
continue;
- if (Buffer[0] == 'n' || Buffer[0] == 'f') {
- *free = Buffer[0];
+ if (c == 'n' || c == 'f') {
+ *free = (unsigned char)c;
break;
} else {
return_error(gs_error_syntaxerror);
@@ -613,9 +633,11 @@ static int read_xref_entry_slow(pdf_context *ctx, pdf_c_stream *s, gs_offset_t *
return_error(gs_error_syntaxerror);
do {
- bytes = pdfi_read_bytes(ctx, &Buffer[0], 1, 1, s);
- read += bytes;
- if (Buffer[0] == 0x20 || Buffer[0] == 0x09 || Buffer[0] == 0x0d || Buffer[0] == 0x0a)
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
+ return_error(gs_error_syntaxerror);
+ read++;
+ if (c == 0x20 || c == 0x09 || c == 0x0d || c == 0x0a)
continue;
} while (read < 20);
return 0;
@@ -626,7 +648,7 @@ static int write_offset(byte *B, gs_offset_t o, unsigned int g, unsigned char fr
byte b[20], *ptr = B;
int index = 0;
- gs_sprintf((char *)b, "%"PRId64"", o);
+ gs_snprintf((char *)b, sizeof(b), "%"PRIdOFFSET"", o);
if (strlen((const char *)b) > 10)
return_error(gs_error_rangecheck);
for(index=0;index < 10 - strlen((const char *)b); index++) {
@@ -636,7 +658,7 @@ static int write_offset(byte *B, gs_offset_t o, unsigned int g, unsigned char fr
ptr += strlen((const char *)b);
*ptr++ = 0x20;
- gs_sprintf((char *)b, "%d", g);
+ gs_snprintf((char *)b, sizeof(b), "%d", g);
if (strlen((const char *)b) > 5)
return_error(gs_error_rangecheck);
for(index=0;index < 5 - strlen((const char *)b);index++) {
@@ -682,6 +704,11 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
return_error(gs_error_typecheck);
}
+ if (((pdf_num *)o)->value.i < 0) {
+ pdfi_pop(ctx, 1);
+ return_error(gs_error_rangecheck);
+ }
+
*section_start = start = ((pdf_num *)o)->value.i;
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
@@ -689,6 +716,10 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
pdfi_pop(ctx, 1);
return code;
}
+ if (code == 0) {
+ pdfi_pop(ctx, 1);
+ return_error(gs_error_syntaxerror);
+ }
o = ctx->stack_top[-1];
if (o->type != PDF_INT) {
@@ -696,6 +727,14 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
pdfi_pop(ctx, 2);
return_error(gs_error_typecheck);
}
+
+ /* Zero sized xref sections are valid; see the file attached to
+ * bug 704947 for an example. */
+ if (((pdf_num *)o)->value.i < 0) {
+ pdfi_pop(ctx, 2);
+ return_error(gs_error_rangecheck);
+ }
+
*section_size = size = ((pdf_num *)o)->value.i;
pdfi_pop(ctx, 2);
@@ -716,7 +755,7 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
return_error(gs_error_VMerror);
}
#if REFCNT_DEBUG
- ctx->xref_table->UID = ctx->UID++;
+ ctx->xref_table->UID = ctx->ref_UID++;
dmprintf1(ctx->memory, "Allocated xref table with UID %"PRIi64"\n", ctx->xref_table->UID);
#endif
@@ -746,7 +785,7 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
return_error(gs_error_ioerror);
j = 19;
while (Buffer[j] != 0x0D && Buffer[j] != 0x0A) {
- pdfi_unread(ctx, s, (byte *)&Buffer[j], 1);
+ pdfi_unread_byte(ctx, s, (byte)Buffer[j]);
if (--j < 0) {
dmprintf(ctx->memory, "Invalid xref entry, line terminator missing.\n");
code = read_xref_entry_slow(ctx, s, &off, &gen, &free);
@@ -755,6 +794,7 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
code = write_offset((byte *)Buffer, off, gen, free);
if (code < 0)
return code;
+ j = 19;
break;
}
}
@@ -762,7 +802,7 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
if (entry->object_num != 0)
continue;
- if (sscanf(Buffer, "%ld %d %c", &entry->u.uncompressed.offset, &entry->u.uncompressed.generation_num, &free) != 3) {
+ if (sscanf(Buffer, "%"PRIdOFFSET" %d %c", &entry->u.uncompressed.offset, &entry->u.uncompressed.generation_num, &free) != 3) {
dmprintf(ctx->memory, "Invalid xref entry, incorrect format.\n");
pdfi_unread(ctx, s, (byte *)Buffer, 20);
code = read_xref_entry_slow(ctx, s, &off, &gen, &free);
@@ -801,8 +841,8 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
if (code < 0)
return code;
- if (section_start + section_size > max_obj)
- max_obj = section_start + section_size;
+ if (section_size > 0 && section_start + section_size - 1 > max_obj)
+ max_obj = section_start + section_size - 1;
if (ctx->stack_top - o > 0) {
k = (pdf_keyword *)ctx->stack_top[-1];
@@ -850,7 +890,7 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
pdfi_pop(ctx, 1);
return code;
}
- if (size < 0) {
+ if (size < 0 || size > floor((double)ARCH_MAX_SIZE_T / (double)sizeof(xref_entry))) {
pdfi_pop(ctx, 1);
return_error(gs_error_rangecheck);
}
@@ -862,7 +902,7 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
}
memset(ctx->xref_table, 0x00, sizeof(xref_table_t));
#if REFCNT_DEBUG
- ctx->xref_table->UID = ctx->UID++;
+ ctx->xref_table->UID = ctx->ref_UID++;
dmprintf1(ctx->memory, "Allocated xref table with UID %"PRIi64"\n", ctx->xref_table->UID);
#endif
@@ -931,6 +971,10 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
return code;
}
+ /* This can happen if pdfi_read_xref_stream tries to repair a broken PDF file */
+ if (d != ctx->Trailer)
+ d = ctx->Trailer;
+
pdfi_loop_detector_cleartomark(ctx);
}
@@ -976,6 +1020,8 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
if (code < 0)
return(code);
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD && ((pdf_keyword *)ctx->stack_top[-1])->key == TOKEN_XREF) {
/* Read old-style xref table */
@@ -1057,21 +1103,21 @@ int pdfi_read_xref(pdf_context *ctx)
entry = &ctx->xref_table->xref[i];
if(entry->compressed) {
dmprintf(ctx->memory, "*");
- gs_sprintf(Buffer, "%ld", entry->object_num);
+ gs_snprintf(Buffer, sizeof(Buffer), "%"PRId64"", entry->object_num);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
}
dmprintf1(ctx->memory, "%s ", Buffer);
- gs_sprintf(Buffer, "%ld", entry->u.compressed.compressed_stream_num);
+ gs_snprintf(Buffer, sizeof(Buffer), "%ld", entry->u.compressed.compressed_stream_num);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
}
dmprintf1(ctx->memory, "%s ", Buffer);
- gs_sprintf(Buffer, "%ld", entry->u.compressed.object_index);
+ gs_snprintf(Buffer, sizeof(Buffer), "%ld", entry->u.compressed.object_index);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
@@ -1081,21 +1127,21 @@ int pdfi_read_xref(pdf_context *ctx)
else {
dmprintf(ctx->memory, " ");
- gs_sprintf(Buffer, "%ld", entry->object_num);
+ gs_snprintf(Buffer, sizeof(Buffer), "%ld", entry->object_num);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
}
dmprintf1(ctx->memory, "%s ", Buffer);
- gs_sprintf(Buffer, "%ld", entry->u.uncompressed.offset);
+ gs_snprintf(Buffer, sizeof(Buffer), "%"PRIdOFFSET"", entry->u.uncompressed.offset);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
}
dmprintf1(ctx->memory, "%s ", Buffer);
- gs_sprintf(Buffer, "%ld", entry->u.uncompressed.generation_num);
+ gs_snprintf(Buffer, sizeof(Buffer), "%ld", entry->u.uncompressed.generation_num);
j = 10 - strlen(Buffer);
while(j--) {
dmprintf(ctx->memory, " ");
diff --git a/pdf/pdfromfs.mak b/pdf/pdfromfs.mak
index bc01a590..527d43c2 100644
--- a/pdf/pdfromfs.mak
+++ b/pdf/pdfromfs.mak
@@ -20,4 +20,4 @@ PDF_FONT_ROMFS_ARGS=
# The -C turns "compaction" on, -B off. For debugging convenience
# it's off just now.
# PDF_ROMFS_ARGS=-d Resource/ -P $(PSRESDIR)$(D) -C CMap$(D)*
-PDF_ROMFS_ARGS=-d Resource/ -P $(PSRESDIR)$(D) -C CMap$(D)* -B Font$(D)* CIDFSubst$(D)* -C Init$(D)Fontmap.GS
+PDF_ROMFS_ARGS=-d Resource/ -P $(PSRESDIR)$(D) -C CMap$(D)* -B Font$(D)* CIDFSubst$(D)* -C Init$(D)Fontmap.GS Init$(D)cidfmap
diff --git a/pdf/pdftop.c b/pdf/pdftop.c
index 6dbe1817..5e147cdd 100644
--- a/pdf/pdftop.c
+++ b/pdf/pdftop.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018-2021 Artifex Software, Inc.
+/* Copyright (C) 2018-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -62,7 +62,7 @@ pdf_detect_language(const char *s, int len)
{
if (len < 5)
return 1;
- return memcmp(s, "%!PDF", 2);
+ return memcmp(s, "%!PDF", 5);
}
static const pl_interp_characteristics_t *
@@ -368,6 +368,7 @@ pdf_impl_report_errors(pl_interp_implementation_t *impl,
return 0;
}
+#if 0
/*
* Get the allocator with which to allocate a device
*/
@@ -379,6 +380,7 @@ pdf_impl_get_device_memory(pl_interp_implementation_t *impl)
return ctx->memory;
}
+#endif
static int plist_value_get_int64(gs_param_typed_value *pvalue, int64_t *pint)
{
@@ -469,31 +471,6 @@ static int plist_value_get_bool(gs_param_typed_value *pvalue, bool *pbool)
return_error(gs_error_typecheck);
}
-/* Get the Overprint value and translate it to a numeric value */
-static int
-pdfi_get_overprint_param(pdf_context *ctx, gs_param_typed_value *pvalue)
-{
- char *val = NULL;
- int len;
- int code;
-
- code = plist_value_get_string_or_name(ctx, pvalue, &val, &len);
- if (code < 0)
- return code;
-
- ctx->args.overprint_control = PDF_OVERPRINT_ENABLE;
- if (val != NULL && !strncmp(val, "disable", len)) {
- ctx->args.overprint_control = PDF_OVERPRINT_DISABLE;
- }
- if (val != NULL && !strncmp(val, "simulate", len)) {
- ctx->args.overprint_control = PDF_OVERPRINT_SIMULATE;
- }
-
- if (val)
- gs_free_object(ctx->memory, val, "Transparency param");
- return code;
-}
-
static int
pdf_impl_set_param(pl_interp_implementation_t *impl,
gs_param_list *plist)
@@ -567,7 +544,7 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
if (code < 0)
return code;
}
- if (!strncmp(param, "NOCIDFALLBACK", 13)) {
+ if (!strncmp(param, "PDFNOCIDFALLBACK", 13)) {
code = plist_value_get_bool(&pvalue, &ctx->args.nocidfallback);
if (code < 0)
return code;
@@ -642,6 +619,11 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
if (code < 0)
return code;
}
+ if (!strncmp(param, "PreserveMarkedContent", 21)) {
+ code = plist_value_get_bool(&pvalue, &ctx->args.preservemarkedcontent);
+ if (code < 0)
+ return code;
+ }
if (!strncmp(param, "NoUserUnit", 10)) {
code = plist_value_get_bool(&pvalue, &ctx->args.nouserunit);
if (code < 0)
@@ -667,11 +649,6 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
if (code < 0)
return code;
}
- if (!strncmp(param, "Overprint", 9)) {
- code = pdfi_get_overprint_param(ctx, &pvalue);
- if (code < 0)
- return code;
- }
if (!strncmp(param, "UsePDFX3Profile", strlen("UsePDFX3Profile"))) {
/* This is a weird one because it can be either a bool or an int.
* If it's a bool=true, then it defaults to PDFX3Profile_num = 0
@@ -705,6 +682,31 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
if (code < 0)
return code;
code = pdfi_add_paths_to_search_paths(ctx, (const char *)s, slen, true);
+ gs_free_object(ctx->memory, s, "FONTPATH param string");
+ }
+ if (!strncmp(param, "FONTMAP", 7)) {
+ char *s = NULL;
+ int slen;
+ code = plist_value_get_string_or_name(ctx, &pvalue, &s, &slen);
+ if (code < 0)
+ return code;
+ code = pdfi_add_fontmapfiles(ctx, (const char *)s, slen);
+ gs_free_object(ctx->memory, s, "FONTMAP param string");
+ }
+ if (!strncmp(param, "CIDSubstPath", 12)) {
+ code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidsubstpath.data, (int *)&ctx->args.cidsubstpath.size);
+ if (code < 0)
+ return code;
+ }
+ if (!strncmp(param, "CIDSubstFont", 12)) {
+ code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidsubstfont.data, (int *)&ctx->args.cidsubstfont.size);
+ if (code < 0)
+ return code;
+ }
+ if (!strncmp(param, "IgnoreToUnicode", 15)) {
+ code = plist_value_get_bool(&pvalue, &ctx->args.ignoretounicode);
+ if (code < 0)
+ return code;
}
}
@@ -776,7 +778,7 @@ pl_interp_implementation_t pdf_implementation =
{
pdf_impl_characteristics,
pdf_impl_allocate_interp_instance,
- pdf_impl_get_device_memory,
+ NULL, /* pdf_impl_get_device_memory, */
pdf_impl_set_param,
pdf_impl_add_path,
pdf_impl_post_args_init,
@@ -843,6 +845,7 @@ pdfi_install_halftone(pdf_context *ctx, gx_device *pdevice)
if (gx_device_must_halftone(pdevice))
{
+ memset(&ht.rc, 0x00, sizeof(ht.rc));
ht.type = ht_type_threshold;
ht.objtype = HT_OBJTYPE_DEFAULT;
ht.params.threshold.width = width;