summaryrefslogtreecommitdiff
path: root/pdf
diff options
context:
space:
mode:
authorSam James <sam@gentoo.org>2022-09-21 14:18:08 +0100
committerSam James <sam@gentoo.org>2022-10-02 04:31:25 +0100
commita529111f77ff46f4836fe7312e70953bc16587cf (patch)
tree9dc3924cb1a6ef3ef853b7bb45f735365e0b4e6d /pdf
parentImport Ghostscript 9.56.1 (diff)
downloadghostscript-gpl-patches-ghostscript-10.tar.gz
ghostscript-gpl-patches-ghostscript-10.tar.bz2
ghostscript-gpl-patches-ghostscript-10.zip
Import Ghostscript 10.0ghostscript-10.0ghostscript-10
Signed-off-by: Sam James <sam@gentoo.org>
Diffstat (limited to 'pdf')
-rw-r--r--pdf/ghostpdf.c222
-rw-r--r--pdf/ghostpdf.h47
-rw-r--r--pdf/pdf.mak2
-rw-r--r--pdf/pdf_annot.c189
-rw-r--r--pdf/pdf_array.c102
-rw-r--r--pdf/pdf_array.h2
-rw-r--r--pdf/pdf_check.c348
-rw-r--r--pdf/pdf_check.h4
-rw-r--r--pdf/pdf_cmap.c33
-rw-r--r--pdf/pdf_colour.c432
-rw-r--r--pdf/pdf_colour.h4
-rw-r--r--pdf/pdf_deref.c394
-rw-r--r--pdf/pdf_dict.c223
-rw-r--r--pdf/pdf_dict.h4
-rw-r--r--pdf/pdf_doc.c406
-rw-r--r--pdf/pdf_errors.h9
-rw-r--r--pdf/pdf_fapi.c166
-rw-r--r--pdf/pdf_file.c137
-rw-r--r--pdf/pdf_fmap.c132
-rw-r--r--pdf/pdf_font.c938
-rw-r--r--pdf/pdf_font.h7
-rw-r--r--pdf/pdf_font0.c66
-rw-r--r--pdf/pdf_font1.c369
-rw-r--r--pdf/pdf_font1.h4
-rw-r--r--pdf/pdf_font11.c84
-rw-r--r--pdf/pdf_font1C.c434
-rw-r--r--pdf/pdf_font1C.h5
-rw-r--r--pdf/pdf_font3.c46
-rw-r--r--pdf/pdf_fontTT.c311
-rw-r--r--pdf/pdf_fontTT.h3
-rw-r--r--pdf/pdf_font_types.h34
-rw-r--r--pdf/pdf_fontps.c39
-rw-r--r--pdf/pdf_fontps.h4
-rw-r--r--pdf/pdf_func.c50
-rw-r--r--pdf/pdf_gstate.c624
-rw-r--r--pdf/pdf_image.c165
-rw-r--r--pdf/pdf_int.c831
-rw-r--r--pdf/pdf_int.h5
-rw-r--r--pdf/pdf_mark.c326
-rw-r--r--pdf/pdf_misc.c9
-rw-r--r--pdf/pdf_misc.h3
-rw-r--r--pdf/pdf_obj.c135
-rw-r--r--pdf/pdf_obj.h88
-rw-r--r--pdf/pdf_optcontent.c135
-rw-r--r--pdf/pdf_page.c304
-rw-r--r--pdf/pdf_page.h26
-rw-r--r--pdf/pdf_path.c458
-rw-r--r--pdf/pdf_pattern.c51
-rw-r--r--pdf/pdf_repair.c153
-rw-r--r--pdf/pdf_sec.c78
-rw-r--r--pdf/pdf_shading.c39
-rw-r--r--pdf/pdf_stack.c108
-rw-r--r--pdf/pdf_stack.h85
-rw-r--r--pdf/pdf_text.c458
-rw-r--r--pdf/pdf_tokens.h116
-rw-r--r--pdf/pdf_trans.c89
-rw-r--r--pdf/pdf_types.h59
-rw-r--r--pdf/pdf_warnings.h11
-rw-r--r--pdf/pdf_xref.c407
-rw-r--r--pdf/pdftop.c28
60 files changed, 6447 insertions, 3594 deletions
diff --git a/pdf/ghostpdf.c b/pdf/ghostpdf.c
index 8d88b090..2dd4c63c 100644
--- a/pdf/ghostpdf.c
+++ b/pdf/ghostpdf.c
@@ -79,10 +79,15 @@ static int pdfi_output_metadata(pdf_context *ctx)
{
int code = 0;
+ if (ctx->filename != NULL)
+ dmprintf2(ctx->memory, "\n %s has %"PRIi64" ", ctx->filename, ctx->num_pages);
+ else
+ dmprintf1(ctx->memory, "\n File has %"PRIi64" ", ctx->num_pages);
+
if (ctx->num_pages > 1)
- dmprintf2(ctx->memory, "\n %s has %"PRIi64" pages\n\n", ctx->filename, ctx->num_pages);
+ dmprintf(ctx->memory, "pages\n\n");
else
- dmprintf2(ctx->memory, "\n %s has %"PRIi64" page.\n\n", ctx->filename, ctx->num_pages);
+ dmprintf(ctx->memory, "page.\n\n");
if (ctx->Info != NULL) {
pdf_name *n = NULL;
@@ -151,6 +156,7 @@ static int pdfi_output_metadata(pdf_context *ctx)
pdfi_countdown(n);
n = NULL;
}
+ dmprintf(ctx->memory, "\n");
return code;
}
@@ -177,7 +183,7 @@ static int pdfi_dump_box(pdf_context *ctx, pdf_dict *page_dict, const char *Key)
if (i != 0)
dmprintf(ctx->memory, " ");
if (code == 0) {
- if (a->values[i]->type == PDF_INT)
+ if (pdfi_type_of(a->values[i]) == PDF_INT)
dmprintf1(ctx->memory, "%"PRIi64"", ((pdf_num *)a->values[i])->value.i);
else
dmprintf1(ctx->memory, "%f", ((pdf_num *)a->values[i])->value.d);
@@ -192,6 +198,90 @@ static int pdfi_dump_box(pdf_context *ctx, pdf_dict *page_dict, const char *Key)
return code;
}
+static int dump_font(pdf_context *ctx, pdf_dict *font_dict, bool space_name)
+{
+ pdf_obj *obj = NULL;
+ char *str = NULL;
+ int len = 0, code = 0, i;
+ bool known = false, type0 = false;
+
+ code = pdfi_dict_get_type(ctx, font_dict, "BaseFont", PDF_NAME, &obj);
+ if (code >= 0) {
+ code = pdfi_string_from_name(ctx, (pdf_name *)obj, &str, &len);
+ if (code >= 0) {
+ dmprintf1(ctx->memory, "%s", str);
+ if (len < 32 && space_name) {
+ for (i = 0; i < 32 - len;i++)
+ dmprintf(ctx->memory, " ");
+ } else
+ dmprintf(ctx->memory, " ");
+ (void)pdfi_free_string_from_name(ctx, str);
+ }
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+
+ code = pdfi_dict_get_type(ctx, font_dict, "Subtype", PDF_NAME, &obj);
+ if (code >= 0) {
+ code = pdfi_string_from_name(ctx, (pdf_name *)obj, &str, &len);
+ if (code >= 0) {
+ dmprintf1(ctx->memory, "%s", str);
+ for (i = 0; i < 16 - len;i++)
+ dmprintf(ctx->memory, " ");
+ (void)pdfi_free_string_from_name(ctx, str);
+ }
+ if (pdfi_name_is((pdf_name *)obj, "Type0"))
+ type0 = true;
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+
+ if (!type0) {
+ code = pdfi_dict_get_type(ctx, font_dict, "Embedded", PDF_BOOL, &obj);
+ if (code >= 0) {
+ if (obj == PDF_FALSE_OBJ)
+ dmprintf(ctx->memory, "Not embedded ");
+ else
+ dmprintf(ctx->memory, "Embedded ");
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+ else
+ dmprintf(ctx->memory, "Not embedded ");
+ } else
+ dmprintf(ctx->memory, " ");
+
+ code = pdfi_dict_get_type(ctx, font_dict, "ToUnicode", PDF_BOOL, &obj);
+ if (code >= 0) {
+ if (obj == PDF_TRUE_OBJ)
+ dmprintf(ctx->memory, "Has ToUnicode ");
+ else
+ dmprintf(ctx->memory, "No ToUnicode ");
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+ else
+ dmprintf(ctx->memory, "No ToUnicode ");
+
+ code = pdfi_dict_known(ctx, font_dict, "Descendants", &known);
+ if (code >= 0 && known) {
+ code = pdfi_dict_get_type(ctx, font_dict, "Descendants", PDF_ARRAY, &obj);
+ if (code >= 0) {
+ pdf_obj *desc = NULL;
+
+ code = pdfi_array_get_type(ctx, (pdf_array *)obj, 0, PDF_DICT, &desc);
+ if (code >= 0) {
+ dmprintf(ctx->memory, "\n Descendants: [");
+ (void)dump_font(ctx, (pdf_dict *)desc, false);
+ dmprintf(ctx->memory, "]");
+ }
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+ }
+ return 0;
+}
+
/*
* This routine along with pdfi_output_metadtaa above, dumps certain kinds
* of metadata from the PDF file, and from each page in the PDF file. It is
@@ -202,12 +292,13 @@ static int pdfi_dump_box(pdf_context *ctx, pdf_dict *page_dict, const char *Key)
* we always emit them, and the switches -dDumpFontsNeeded, -dDumpXML,
* -dDumpFontsUsed and -dShowEmbeddedFonts are not implemented at all yet.
*/
-static int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
+int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
{
int code;
bool known = false;
double f;
pdf_dict *page_dict = NULL;
+ pdf_array *fonts_array = NULL, *spots_array = NULL;
code = pdfi_page_get_dict(ctx, page_num, &page_dict);
if (code < 0)
@@ -271,7 +362,7 @@ static int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
return code;
}
- code = pdfi_check_page(ctx, page_dict, false);
+ code = pdfi_check_page(ctx, page_dict, &fonts_array, &spots_array, false);
if (code < 0) {
if (ctx->args.pdfstoponerror)
return code;
@@ -283,16 +374,62 @@ static int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num)
code = pdfi_dict_known(ctx, page_dict, "Annots", &known);
if (code < 0) {
if (code != gs_error_undefined && ctx->args.pdfstoponerror)
- return code;
+ goto error;
} else {
if (known == true)
dmprintf(ctx->memory, " Page contains Annotations");
+ code = 0;
+ }
+
+ if (spots_array != NULL) {
+ uint64_t index = 0;
+ pdf_name *spot = NULL;
+ char *str = NULL;
+ int len;
+
+ dmprintf(ctx->memory, "\n Page Spot colors: \n");
+ for (index = 0;index < pdfi_array_size(spots_array);index++) {
+ code = pdfi_array_get(ctx, spots_array, index, (pdf_obj **)&spot);
+ if (code >= 0) {
+ if (pdfi_type_of(spot) == PDF_NAME) {
+ code = pdfi_string_from_name(ctx, spot, &str, &len);
+ if (code >= 0) {
+ dmprintf1(ctx->memory, " '%s'\n", str);
+ (void)pdfi_free_string_from_name(ctx, str);
+ }
+ }
+ pdfi_countdown(spot);
+ spot = NULL;
+ }
+ }
+ code = 0;
}
+ if (fonts_array != NULL && pdfi_array_size(fonts_array) != 0) {
+ uint64_t index = 0;
+ pdf_dict *font_dict = NULL;
+
+ dmprintf(ctx->memory, "\n Fonts used: \n");
+ for (index = 0;index < pdfi_array_size(fonts_array);index++) {
+ code = pdfi_array_get_type(ctx, fonts_array, index, PDF_DICT, (pdf_obj **)&font_dict);
+ if (code >= 0) {
+ dmprintf(ctx->memory, " ");
+ (void)dump_font(ctx, font_dict, true);
+ dmprintf(ctx->memory, "\n");
+ pdfi_countdown(font_dict);
+ font_dict = NULL;
+ }
+ }
+ code = 0;
+ }
+
+error:
+ pdfi_countdown(fonts_array);
+ pdfi_countdown(spots_array);
dmprintf(ctx->memory, "\n\n");
pdfi_countdown(page_dict);
- return 0;
+ return code;
}
/* Error and warning string tables. There should be a string for each error and warning
@@ -347,6 +484,8 @@ const char *gs_error_strings[] = {
"unregistered",
"invalidcontext",
"invalidid",
+ "pdf_stackoverflow",
+ "circular reference"
};
const char *gs_internal_error_strings[] = {
@@ -358,16 +497,15 @@ const char *gs_internal_error_strings[] = {
"exec stack underflow",
"VMreclaim",
"Need input",
+ "need file",
"No defined error",
"No defined error (2)",
- "need file",
"error info",
"handled",
- "circular reference"
};
-#define LASTNORMALGSERROR gs_error_invalidid * -1
+#define LASTNORMALGSERROR gs_error_circular_reference * -1
#define FIRSTINTERNALERROR gs_error_hit_detected * -1
-#define LASTGSERROR gs_error_circular_reference * -1
+#define LASTGSERROR gs_error_handled * -1
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)
{
@@ -784,7 +922,7 @@ int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_a
if (code < 0)
goto exit;
- if (File->type == PDF_DICT) {
+ if (pdfi_type_of(File) == PDF_DICT) {
if (pdfi_dict_knownget_type(ctx, (pdf_dict *)File, "EF", PDF_DICT, &EF)) {
if (pdfi_dict_knownget_type(ctx, (pdf_dict *)EF, "F", PDF_STREAM, &F)) {
pdf_dict *stream_dict = NULL;
@@ -859,7 +997,7 @@ int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_a
/* Create an entry for the Description in the names array */
code = pdfi_array_get(ctx, FileNames, ix * 2, (pdf_obj **)&Name);
if (code >= 0) {
- if (Name->type == PDF_STRING) {
+ if (pdfi_type_of((pdf_obj *)Name) == PDF_STRING) {
working_array[(index * 2) + 1] = (char *)gs_alloc_bytes(ctx->memory, Name->length + 3, "Collection file names array entry");
if (working_array[(index * 2) + 1] != NULL) {
memset(working_array[(index * 2) + 1], 0x00, Name->length + 3);
@@ -999,6 +1137,13 @@ int pdfi_process_pdf_file(pdf_context *ctx, char *filename)
else
code = pdfi_process(ctx);
+ /* Pdfmark_InitialPage is the offset for Page Dests in
+ * /Outlines and Link annotations. It is the count of pages
+ * processed so far. Update it by the number of pages in
+ * this file.
+ */
+ ctx->Pdfmark_InitialPage += ctx->num_pages;
+
pdfi_close_pdf_file(ctx);
return code;
}
@@ -1037,9 +1182,14 @@ static int pdfi_init_file(pdf_context *ctx)
if (code < 0 && code != gs_error_undefined)
goto exit;
if (code == 0) {
- code = pdfi_initialise_Decryption(ctx);
- if (code < 0)
- goto exit;
+ if (pdfi_type_of(o) == PDF_DICT) {
+ code = pdfi_initialise_Decryption(ctx);
+ if (code < 0)
+ goto exit;
+ } else {
+ if (pdfi_type_of(o) != PDF_NULL)
+ pdfi_set_error(ctx, code, NULL, E_PDF_BADENCRYPT, "pdfi_init_file", NULL);
+ }
}
}
@@ -1144,6 +1294,7 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
}
/* Determine file size */
+ pdfi_seek(ctx, ctx->main_stream, 0, SEEK_SET);
pdfi_seek(ctx, ctx->main_stream, 0, SEEK_END);
ctx->main_stream_length = pdfi_tell(ctx->main_stream);
Offset = BUF_SIZE;
@@ -1268,8 +1419,15 @@ int pdfi_set_input_stream(pdf_context *ctx, stream *stm)
*/
if (last_lineend) {
leftover = last_lineend - Buffer;
- memmove(Buffer + bytes - leftover, last_lineend, leftover);
- bytes -= leftover;
+ /* Ensure we don't try to copy more than half a buffer, because that will
+ * end up overrunning the buffer end. Since we are only doing this to
+ * ensure we don't drop a partial 'startxref' that's far more than enough.
+ */
+ if (leftover < BUF_SIZE / 2) {
+ memmove(Buffer + bytes - leftover, last_lineend, leftover);
+ bytes -= leftover;
+ } else
+ leftover = 0;
} else
leftover = 0;
}
@@ -1757,6 +1915,15 @@ int pdfi_clear_context(pdf_context *ctx)
dmprintf1(ctx->memory, "Normal object cache hit rate: %f\n", hit_rate);
dmprintf1(ctx->memory, "Compressed object cache hit rate: %f\n", compressed_hit_rate);
#endif
+ if (ctx->PathSegments != NULL) {
+ gs_free_object(ctx->memory, ctx->PathSegments, "pdfi_clear_context");
+ ctx->PathSegments = NULL;
+ }
+ if (ctx->PathPts != NULL) {
+ gs_free_object(ctx->memory, ctx->PathPts, "pdfi_clear_context");
+ ctx->PathPts = NULL;
+ }
+
if (ctx->args.PageList) {
gs_free_object(ctx->memory, ctx->args.PageList, "pdfi_clear_context");
ctx->args.PageList = NULL;
@@ -1786,14 +1953,19 @@ 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.cidfsubstpath.data != NULL) {
+ gs_free_object(ctx->memory, ctx->args.cidfsubstpath.data, "cidfsubstpath.data");
+ ctx->args.cidfsubstpath.data = NULL;
+ }
+
+ if (ctx->args.cidfsubstfont.data != NULL) {
+ gs_free_object(ctx->memory, ctx->args.cidfsubstfont.data, "cidfsubstfont.data");
+ ctx->args.cidfsubstfont.data = NULL;
}
- if (ctx->args.cidsubstfont.data != NULL) {
- gs_free_object(ctx->memory, ctx->args.cidsubstfont.data, "cidsubstpath.data");
- ctx->args.cidsubstfont.data = NULL;
+ if (ctx->args.defaultfont.data != NULL) {
+ gs_free_object(ctx->memory, ctx->args.defaultfont.data, "cidfsubstfont.data");
+ ctx->args.defaultfont.data = NULL;
}
pdfi_free_cstring_array(ctx, &ctx->args.showannottypes);
@@ -1923,6 +2095,8 @@ int pdfi_clear_context(pdf_context *ctx)
ctx->pdffontmap = NULL;
pdfi_countdown(ctx->pdfnativefontmap);
ctx->pdfnativefontmap = NULL;
+ pdfi_countdown(ctx->pdf_substitute_fonts);
+ ctx->pdf_substitute_fonts = NULL;
return 0;
}
diff --git a/pdf/ghostpdf.h b/pdf/ghostpdf.h
index 49c91808..1c2ffe78 100644
--- a/pdf/ghostpdf.h
+++ b/pdf/ghostpdf.h
@@ -22,6 +22,12 @@
#define BUF_SIZE 2048
+/* Limit nesting of arrays and dictionaries. We don't want to allow this
+ * to be unbounded, because on exit we could end up exceeding the C execution stack
+ * if we get too deeply nested.
+ */
+#define MAX_NESTING_DEPTH 100
+
#include "pdf_types.h"
#if defined(MEMENTO)
@@ -143,8 +149,11 @@ typedef struct cmd_args_s {
bool QUIET;
bool verbose_errors;
bool verbose_warnings;
- gs_string cidsubstpath;
- gs_string cidsubstfont;
+ gs_string cidfsubstpath;
+ gs_string cidfsubstfont;
+ gs_string defaultfont;
+ bool defaultfont_is_name;
+
bool ignoretounicode;
bool nonativefontmap;
} cmd_args_t;
@@ -321,6 +330,11 @@ typedef struct pdf_context_s
/* Doing a high level form for pdfwrite (annotations) */
bool PreservePDFForm;
+ /* If processing multiple files, the number of pages to add to /Page Destinations
+ * when handling Outlines and Annotations. This is the number of pages in all
+ * files completely processed so far.
+ */
+ int Pdfmark_InitialPage;
/* Optional things from Root */
pdf_dict *OCProperties;
@@ -339,6 +353,27 @@ typedef struct pdf_context_s
gs_font_dir * font_dir;
/* Obviously we need a graphics state */
gs_gstate *pgs;
+
+ /* PDF really doesn't have a path in the graphics state. This is different to
+ * PostScript and has implications; changing the CTM partway through path
+ * construction affects path segments already accumulated. The path is
+ * unaffected by gsvae and grestore. Previously we've unwound any pending
+ * path and rerun it, this is causing problems so instead we'll do what
+ * Acrobat obviously does and build the path outside the graphics state
+ */
+ /* We make allocations in chunks for the path to avoid lots of little
+ * allocations, but we need to know where the end of the current allocation
+ * is so that we can tell if we would overflow and increase it.
+ */
+ char *PathSegments;
+ /* The current insertion point. */
+ char *PathSegmentsCurrent;
+ /* The current limit of the block */
+ char *PathSegmentsTop;
+ double *PathPts;
+ double *PathPtsCurrent;
+ double *PathPtsTop;
+
/* set up by pdf_impl_set_device, this is the 'high water mark' for
* restoring back to when we close a PDF file. This ensures the device
* is correctly set up for any subesquent file to be run.
@@ -406,6 +441,12 @@ typedef struct pdf_context_s
uint32_t loop_detection_entries;
uint64_t *loop_detection;
+ /* A counter for nesting of arrays and dictionaries. We don't want to allow this
+ * to be unbounded, because on exit we could end up exceeding the C execution stack
+ * if we get too deeply nested.
+ */
+ uint32_t object_nesting;
+
/* Used to set the 'parent' stream of a stream that gets created by dereferencing
* We should not need this but badly fromed PDF files can use Resources defined in
* an earlier (non-Page) stream object, and Acrobat handles this, so we need to.
@@ -423,6 +464,7 @@ typedef struct pdf_context_s
search_paths_t search_paths;
pdf_dict *pdffontmap;
pdf_dict *pdfnativefontmap; /* Explicit mappings take precedence, hence we need separate dictionaries */
+ pdf_dict *pdf_substitute_fonts;
pdf_dict *pdfcidfmap;
/* These function pointers can be replaced by ones intended to replicate
@@ -468,6 +510,7 @@ int pdfi_prep_collection(pdf_context *ctx, uint64_t *TotalFiles, char ***names_a
int pdfi_close_pdf_file(pdf_context *ctx);
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);
+int pdfi_output_page_info(pdf_context *ctx, uint64_t page_num);
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);
diff --git a/pdf/pdf.mak b/pdf/pdf.mak
index 7040a72e..118a0b7d 100644
--- a/pdf/pdf.mak
+++ b/pdf/pdf.mak
@@ -188,7 +188,7 @@ $(PDFOBJ)pdf_stack.$(OBJ): $(PDFSRC)pdf_stack.c $(PDFINCLUDES) $(PDF_MAK) $(MAKE
$(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)
+ $(gscoord_h) $(gsutil_h) $(gscolor3_h) $(PDF_MAK) $(MAKEDIRS) $(gzpath_h) $(gspenum_h)
$(PDFCCC) $(PDFSRC)pdf_gstate.c $(PDFO_)pdf_gstate.$(OBJ)
$(PDFOBJ)pdf_colour.$(OBJ): $(PDFSRC)pdf_colour.c $(PDFINCLUDES) \
diff --git a/pdf/pdf_annot.c b/pdf/pdf_annot.c
index 7b96be1c..83b79293 100644
--- a/pdf/pdf_annot.c
+++ b/pdf/pdf_annot.c
@@ -269,7 +269,7 @@ static int pdfi_annot_draw_AP(pdf_context *ctx, pdf_dict *annot, pdf_obj *NormAP
if (NormAP == NULL)
return 0;
- if (NormAP->type != PDF_STREAM)
+ if (pdfi_type_of(NormAP) != PDF_STREAM)
return_error(gs_error_typecheck);
code = pdfi_op_q(ctx);
@@ -649,11 +649,55 @@ static int pdfi_form_get_inheritable(pdf_context *ctx, pdf_dict *field, const ch
{
int code = 0;
pdf_dict *Parent = NULL;
+ bool known = false;
/* Check this field */
code = pdfi_dict_knownget_type(ctx, field, Key, type, o);
- if (code != 0) goto exit;
+ if (code != 0) goto exit1;
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ goto exit;
+
+ /* Check for Parent. Do not store the dereferenced Parent back to the dictionary
+ * as this can cause circular references.
+ */
+ code = pdfi_dict_known(ctx, field, "Parent", &known);
+ if (code >= 0 && known == true)
+ {
+ code = pdfi_dict_get_no_store_R(ctx, field, "Parent", (pdf_obj **)&Parent);
+ if (code < 0)
+ goto exit;
+
+ if (pdfi_type_of(Parent) != PDF_DICT) {
+ if (pdfi_type_of(Parent) == PDF_INDIRECT) {
+ pdf_indirect_ref *o = (pdf_indirect_ref *)Parent;
+
+ code = pdfi_dereference(ctx, o->ref_object_num, o->ref_generation_num, (pdf_obj **)&Parent);
+ pdfi_countdown(o);
+ goto exit;
+ } else {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ }
+ if (Parent->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, Parent->object_num);
+ if (code < 0)
+ goto exit;
+ }
+ code = pdfi_form_get_inheritable(ctx, Parent, Key, type, o);
+ if (code <= 0) {
+ if (ctx->AcroForm)
+ code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
+ }
+ } else {
+ /* No Parent, so check AcroForm, if any */
+ if (ctx->AcroForm)
+ code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
+ }
+
+#if 0
/* If not found, recursively check Parent, if any */
code = pdfi_dict_knownget_type(ctx, field, "Parent", PDF_DICT, (pdf_obj **)&Parent);
if (code < 0) goto exit;
@@ -665,8 +709,12 @@ static int pdfi_form_get_inheritable(pdf_context *ctx, pdf_dict *field, const ch
if (ctx->AcroForm)
code = pdfi_dict_knownget_type(ctx, ctx->AcroForm, Key, type, o);
}
+#endif
- exit:
+exit:
+ (void)pdfi_loop_detector_cleartomark(ctx);
+
+exit1:
pdfi_countdown(Parent);
return code;
}
@@ -1475,11 +1523,13 @@ static int pdfi_annot_draw_LE(pdf_context *ctx, pdf_dict *annot,
double dx, dy;
double angle;
int code;
+ pdf_obj_type type;
code = pdfi_dict_knownget(ctx, annot, "LE", (pdf_obj **)&LE);
if (code <= 0)
goto exit;
- if (LE->type != PDF_ARRAY && LE->type != PDF_NAME) {
+ type = pdfi_type_of(LE);
+ if (type != PDF_ARRAY && type != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -1490,7 +1540,7 @@ static int pdfi_annot_draw_LE(pdf_context *ctx, pdf_dict *annot,
if (code < 0)
angle = 0;
- if (LE->type == PDF_ARRAY) {
+ if (type == PDF_ARRAY) {
code = pdfi_array_get_type(ctx, (pdf_array *)LE, 0, PDF_NAME, (pdf_obj **)&LE1);
if (code < 0) goto exit;
@@ -1554,34 +1604,35 @@ static int pdfi_annot_get_NormAP(pdf_context *ctx, pdf_dict *annot, pdf_obj **No
/* Nothing found */
if (code == 0) goto exit;
- if (baseAP->type == PDF_STREAM) {
- /* Use baseAP for the AP */
- AP = (pdf_stream *)baseAP;
- baseAP = NULL;
- } else {
- if (baseAP->type != PDF_DICT) {
- code = gs_error_typecheck;
- goto exit;
- }
-
- code = pdfi_dict_knownget_type(ctx, annot, "AS", PDF_NAME, (pdf_obj **)&AS);
- if (code < 0) goto exit;
- if (code == 0) {
- pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_AP_ERROR, "pdfi_annot_get_NormAP", "WARNING Annotation has non-stream AP but no AS. Don't know what to render");
- goto exit;
- }
+ switch (pdfi_type_of(baseAP)) {
+ case PDF_STREAM:
+ /* Use baseAP for the AP */
+ AP = (pdf_stream *)baseAP;
+ baseAP = NULL;
+ break;
+ case PDF_DICT:
+ code = pdfi_dict_knownget_type(ctx, annot, "AS", PDF_NAME, (pdf_obj **)&AS);
+ if (code < 0) goto exit;
+ if (code == 0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_ANNOT_AP_ERROR, "pdfi_annot_get_NormAP", "WARNING Annotation has non-stream AP but no AS. Don't know what to render");
+ goto exit;
+ }
- /* Lookup the AS in the NormAP and use that as the AP */
- code = pdfi_dict_get_by_key(ctx, (pdf_dict *)baseAP, AS, (pdf_obj **)&AP);
- if (code < 0) {
- /* Apparently this is not an error, just silently don't have an AP */
- code = 0;
- goto exit;
- }
- if (AP->type != PDF_STREAM) {
- code = gs_note_error(gs_error_typecheck);
+ /* Lookup the AS in the NormAP and use that as the AP */
+ code = pdfi_dict_get_by_key(ctx, (pdf_dict *)baseAP, AS, (pdf_obj **)&AP);
+ if (code < 0) {
+ /* Apparently this is not an error, just silently don't have an AP */
+ code = 0;
+ goto exit;
+ }
+ if (pdfi_type_of(AP) != PDF_STREAM) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ break;
+ default:
+ code = gs_error_typecheck;
goto exit;
- }
}
*NormAP = (pdf_obj *)AP;
@@ -3630,9 +3681,9 @@ static int pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, pdf_obj *No
{
int code = 0;
bool found_T = false;
- bool found_TF = false;
+ bool found_FT = false, known = false;
pdf_obj *T = NULL;
- pdf_obj *TF = NULL;
+ pdf_obj *FT = NULL;
pdf_dict *Parent = NULL;
pdf_dict *currdict = NULL;
@@ -3651,33 +3702,71 @@ static int pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, pdf_obj *No
/* TODO: See top part of pdf_draw.ps/drawwidget
* check for /FT and /T and stuff
*/
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ goto exit;
+
currdict = annot;
pdfi_countup(currdict);
while (true) {
+ if (currdict->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, currdict->object_num);
+ if (code < 0)
+ break;
+ }
+
code = pdfi_dict_knownget(ctx, currdict, "T", &T);
if (code < 0) goto exit;
if (code > 0) {
found_T = true;
- break;
+ pdfi_countdown(T);
+ T = NULL;
+ if (found_FT)
+ break;
}
- code = pdfi_dict_knownget(ctx, currdict, "TF", &TF);
+ code = pdfi_dict_knownget(ctx, currdict, "FT", &FT);
if (code < 0) goto exit;
if (code > 0) {
- found_TF = true;
- break;
+ found_FT = true;
+ pdfi_countdown(FT);
+ FT = NULL;
+ if (found_T)
+ break;
}
- /* Check for Parent */
- code = pdfi_dict_knownget_type(ctx, currdict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
- if (code < 0) goto exit;
- if (code == 0)
+ /* Check for Parent. Do not store the dereferenced Parent back to the dictionary
+ * as this can cause circular references.
+ */
+ code = pdfi_dict_known(ctx, currdict, "Parent", &known);
+ if (code >= 0 && known == true)
+ {
+ code = pdfi_dict_get_no_store_R(ctx, currdict, "Parent", (pdf_obj **)&Parent);
+ if (code < 0) {
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ goto exit;
+ }
+ if (pdfi_type_of(Parent) != PDF_DICT) {
+ if (pdfi_type_of(Parent) == PDF_INDIRECT) {
+ pdf_indirect_ref *o = (pdf_indirect_ref *)Parent;
+
+ code = pdfi_dereference(ctx, o->ref_object_num, o->ref_generation_num, (pdf_obj **)&Parent);
+ pdfi_countdown(o);
+ if (code < 0)
+ break;
+ } else {
+ break;
+ }
+ }
+ pdfi_countdown(currdict);
+ currdict = Parent;
+ Parent = NULL;
+ } else
break;
- pdfi_countdown(currdict);
- currdict = Parent;
- pdfi_countup(currdict);
}
+ (void)pdfi_loop_detector_cleartomark(ctx);
+
code = 0;
- if (!found_T && !found_TF) {
+ if (!found_T || !found_FT) {
*render_done = true;
dmprintf(ctx->memory, "**** Warning: A Widget annotation dictionary lacks either the FT or T key.\n");
dmprintf(ctx->memory, " Acrobat ignores such annoataions, annotation will not be rendered.\n");
@@ -3696,8 +3785,6 @@ static int pdfi_annot_draw_Widget(pdf_context *ctx, pdf_dict *annot, pdf_obj *No
*render_done = true;
exit:
- pdfi_countdown(T);
- pdfi_countdown(TF);
pdfi_countdown(Parent);
pdfi_countdown(currdict);
return code;
@@ -3950,7 +4037,7 @@ static int pdfi_annot_preserve_modQP(pdf_context *ctx, pdf_dict *annot, pdf_name
code = pdfi_dict_get(ctx, annot, "QuadPoints", (pdf_obj **)&QP);
if (code < 0) goto exit;
- if (QP->type != PDF_ARRAY) {
+ if (pdfi_type_of(QP) != PDF_ARRAY) {
/* Invalid QuadPoints, just delete it because I dunno what to do...
* TODO: Should flag a warning here
*/
@@ -4024,7 +4111,7 @@ static int pdfi_annot_preserve_modAP(pdf_context *ctx, pdf_dict *annot, pdf_name
code = pdfi_dict_get(ctx, annot, "AP", (pdf_obj **)&AP);
if (code < 0) goto exit;
- if (AP->type != PDF_DICT) {
+ if (pdfi_type_of(AP) != PDF_DICT) {
/* This is an invalid AP, we will flag and delete it below */
found_ap = false;
goto exit;
@@ -4037,14 +4124,14 @@ static int pdfi_annot_preserve_modAP(pdf_context *ctx, pdf_dict *annot, pdf_name
if (code < 0) goto exit;
/* Handle indirect object */
- if (Value->type != PDF_INDIRECT)
+ if (pdfi_type_of(Value) != PDF_INDIRECT)
goto loop_continue;
/* Dereference it */
code = pdfi_dereference(ctx, Value->ref_object_num, Value->ref_generation_num, &object);
if (code < 0) goto exit;
- if (object->type == PDF_STREAM) {
+ if (pdfi_type_of(object) == PDF_STREAM) {
/* Get a form label */
code = pdfi_annot_preserve_nextformlabel(ctx, &labeldata, &labellen);
if (code < 0) goto exit;
diff --git a/pdf/pdf_array.c b/pdf/pdf_array.c
index 5f269fe5..0cdb3365 100644
--- a/pdf/pdf_array.c
+++ b/pdf/pdf_array.c
@@ -20,6 +20,7 @@
#include "pdf_stack.h"
#include "pdf_deref.h"
#include "pdf_array.h"
+#include "pdf_loop_detect.h"
/* NOTE: I think this should take a pdf_context param, but it's not available where it's
* called, would require some surgery.
@@ -40,7 +41,6 @@ void pdfi_free_array(pdf_obj *o)
int pdfi_array_alloc(pdf_context *ctx, uint64_t size, pdf_array **a)
{
int code, i;
- pdf_obj *n = NULL;
*a = NULL;
code = pdfi_object_alloc(ctx, PDF_ARRAY, size, (pdf_obj **)a);
@@ -50,22 +50,14 @@ int pdfi_array_alloc(pdf_context *ctx, uint64_t size, pdf_array **a)
(*a)->size = size;
if (size > 0) {
- /* Make a null object */
- code = pdfi_object_alloc(ctx, PDF_NULL, 1, &n);
- if (code < 0) {
- pdfi_free_object((pdf_obj *)(*a));
- *a = NULL;
- return code;
- }
- /* And start all the array entries pointing at that null object.
+ /* Start all the array entries pointing to null.
* array_put will replace tehm. This ensures we always have a valid
* object for every entry. pdfi_array_from_stack() doesn't do this
* initialisation because we know how many obejcts there are in the array
* and we have valid objects for each entry on the stack already created.
*/
for (i=0;i<size;i++){
- (*a)->values[i] = n;
- pdfi_countup(n);
+ (*a)->values[i] = PDF_NULL_OBJ;
}
}
return 0;
@@ -118,6 +110,48 @@ int pdfi_array_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indi
return code;
}
+int pdfi_array_fetch_recursing(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache)
+{
+ int code;
+ pdf_obj *obj;
+
+ *o = NULL;
+
+ if (pdfi_type_of(a) != PDF_ARRAY)
+ return_error(gs_error_typecheck);
+
+ if (index >= a->size)
+ return_error(gs_error_rangecheck);
+ obj = a->values[index];
+
+ if (pdfi_type_of(obj) == PDF_INDIRECT) {
+ pdf_obj *o1 = NULL;
+ pdf_indirect_ref *r = (pdf_indirect_ref *)obj;
+
+ 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;
+
+ if (setref)
+ (void)pdfi_array_put(ctx, a, index, o1);
+ obj = o1;
+ } else {
+ if (ctx->loop_detection != NULL && (uintptr_t)obj > TOKEN__LAST_KEY && obj->object_num != 0)
+ if (pdfi_loop_detector_check_object(ctx, obj->object_num))
+ return gs_note_error(gs_error_circular_reference);
+ pdfi_countup(obj);
+ }
+
+ *o = obj;
+ return 0;
+}
+
/* Fetch object from array, resolving indirect reference if needed
* setref -- indicates whether to replace indirect ref with the object
*/
@@ -128,14 +162,14 @@ int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o
*o = NULL;
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
if (index >= a->size)
return_error(gs_error_rangecheck);
obj = a->values[index];
- if (obj->type == PDF_INDIRECT) {
+ if (pdfi_type_of(obj) == PDF_INDIRECT) {
pdf_obj *o1 = NULL;
pdf_indirect_ref *r = (pdf_indirect_ref *)obj;
@@ -166,7 +200,7 @@ int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o
*/
int pdfi_array_get_no_deref(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
{
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
if (index >= a->size)
@@ -201,7 +235,7 @@ int pdfi_array_get_type(pdf_context *ctx, pdf_array *a, uint64_t index,
if (code < 0)
return code;
- if ((*o)->type != type) {
+ if (pdfi_type_of(*o) != type) {
pdfi_countdown(*o);
*o = NULL;
return_error(gs_error_typecheck);
@@ -212,34 +246,26 @@ int pdfi_array_get_type(pdf_context *ctx, pdf_array *a, uint64_t index,
int pdfi_array_get_int(pdf_context *ctx, pdf_array *a, uint64_t index, int64_t *i)
{
int code;
- pdf_num *n;
+ pdf_obj *n;
- code = pdfi_array_get_type(ctx, a, index, PDF_INT, (pdf_obj **)&n);
+ code = pdfi_array_get(ctx, a, index, &n);
if (code < 0)
return code;
- *i = n->value.i;
+ code = pdfi_obj_to_int(ctx, n, i);
pdfi_countdown(n);
- return 0;
+ return code;
}
-int pdfi_array_get_number(pdf_context *ctx, pdf_array *a, uint64_t index, double *f)
+int pdfi_array_get_number(pdf_context *ctx, pdf_array *a, uint64_t index, double *d)
{
int code;
- pdf_num *n;
+ pdf_obj *n;
- code = pdfi_array_get(ctx, a, index, (pdf_obj **)&n);
+ code = pdfi_array_get(ctx, a, index, &n);
if (code < 0)
return code;
- if (n->type == PDF_INT)
- *f = (double)n->value.i;
- else {
- if (n->type == PDF_REAL)
- *f = n->value.d;
- else {
- code = gs_note_error(gs_error_typecheck);
- }
- }
+ code = pdfi_obj_to_real(ctx, n, d);
pdfi_countdown(n);
return code;
@@ -253,7 +279,7 @@ bool pdfi_array_known(pdf_context *ctx, pdf_array *a, pdf_obj *o, int *index)
{
int i;
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
for (i=0; i < a->size; i++) {
@@ -263,7 +289,7 @@ bool pdfi_array_known(pdf_context *ctx, pdf_array *a, pdf_obj *o, int *index)
code = pdfi_array_fetch(ctx, a, i, &val, true, true);
if (code < 0)
continue;
- if (val->object_num == o->object_num) {
+ if (pdf_object_num(val) == pdf_object_num(o)) {
if (index != NULL) *index = i;
pdfi_countdown(val);
return true;
@@ -275,7 +301,7 @@ bool pdfi_array_known(pdf_context *ctx, pdf_array *a, pdf_obj *o, int *index)
int pdfi_array_put(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj *o)
{
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
if (index >= a->size)
@@ -292,7 +318,7 @@ int pdfi_array_put_int(pdf_context *ctx, pdf_array *a, uint64_t index, int64_t v
int code;
pdf_num *obj;
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&obj);
@@ -308,7 +334,7 @@ int pdfi_array_put_real(pdf_context *ctx, pdf_array *a, uint64_t index, double v
int code;
pdf_num *obj;
- if (a->type != PDF_ARRAY)
+ if (pdfi_type_of(a) != PDF_ARRAY)
return_error(gs_error_typecheck);
code = pdfi_object_alloc(ctx, PDF_REAL, 0, (pdf_obj **)&obj);
@@ -358,7 +384,7 @@ int pdfi_array_to_gs_rect(pdf_context *ctx, pdf_array *array, gs_rect *rect)
rect->q.y = 1.0;
/* Identity matrix if no array */
- if (array == NULL || array->type != PDF_ARRAY) {
+ if (array == NULL || pdfi_type_of(array) != PDF_ARRAY) {
return 0;
}
if (pdfi_array_size(array) != 4) {
@@ -451,7 +477,7 @@ int pdfi_array_to_gs_matrix(pdf_context *ctx, pdf_array *array, gs_matrix *mat)
mat->ty = 0.0;
/* Identity matrix if no array */
- if (array == NULL || array->type != PDF_ARRAY) {
+ if (array == NULL || pdfi_type_of(array) != PDF_ARRAY) {
return 0;
}
if (pdfi_array_size(array) != 6) {
diff --git a/pdf/pdf_array.h b/pdf/pdf_array.h
index 37097aaa..a4eb7d35 100644
--- a/pdf/pdf_array.h
+++ b/pdf/pdf_array.h
@@ -55,4 +55,6 @@ int pdfi_array_to_gs_matrix(pdf_context *ctx, pdf_array *array, gs_matrix *matri
int pdfi_array_to_num_array(pdf_context *ctx, pdf_array *array, double *out, int start, int size);
void pdfi_bbox_transform(pdf_context *ctx, gs_rect *bbox, gs_matrix *matrix);
+int pdfi_array_fetch_recursing(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache);
+
#endif
diff --git a/pdf/pdf_check.c b/pdf/pdf_check.c
index 00933bdf..19a6d957 100644
--- a/pdf/pdf_check.c
+++ b/pdf/pdf_check.c
@@ -66,7 +66,7 @@
* stores all the objects (which we don't want to do because its wasteful) and checking
* to see if its already tested a given resource for spots/transparency.
* This is a temporary allocation, big enough to hold all the objects in the file (1 per bit)
- * each time we have fully checked a resource we add it here, when checking a resoruce we
+ * each time we have fully checked a resource we add it here, when checking a resource we
* first check this list to see if its already been checked, in which case we can skip
* it. When done we release the memory.
*/
@@ -74,6 +74,7 @@ typedef struct {
bool transparent;
bool has_overprint; /* Does it have OP or op in an ExtGState? */
pdf_dict *spot_dict;
+ pdf_array *font_array;
uint32_t size;
byte *CheckedResources;
} pdfi_check_tracker_t;
@@ -84,6 +85,7 @@ static inline bool resource_is_checked(pdfi_check_tracker_t *tracker, pdf_obj *o
{
uint32_t byte_offset;
byte bit_offset;
+ int object_num;
if(tracker->CheckedResources == NULL)
return 0;
@@ -91,14 +93,15 @@ static inline bool resource_is_checked(pdfi_check_tracker_t *tracker, pdf_obj *o
/* objects with object number 0 are directly defined, we can't
* store those so just return immediately
*/
- if (o->object_num > 0 && (o->object_num >> 3) < tracker->size) {
+ object_num = pdf_object_num(o);
+ if (object_num > 0 && (object_num >> 3) < tracker->size) {
/* CheckedResources is a byte array, each byte represents
* 8 objects. So the object number / 8 is the byte offset
* into the array, and then object number % 8 is the bit
* within that byte that we want.
*/
- bit_offset = 0x01 << (o->object_num % 8);
- byte_offset = o->object_num >> 3;
+ bit_offset = 0x01 << (object_num % 8);
+ byte_offset = object_num >> 3;
/* If its already set, then return that. */
if (tracker->CheckedResources[byte_offset] & bit_offset)
@@ -116,12 +119,13 @@ pdfi_check_free_tracker(pdf_context *ctx, pdfi_check_tracker_t *tracker)
{
gs_free_object(ctx->memory, tracker->CheckedResources, "pdfi_check_free_tracker(flags)");
pdfi_countdown(tracker->spot_dict);
+ pdfi_countdown(tracker->font_array);
memset(tracker, 0, sizeof(*tracker));
return 0;
}
static int
-pdfi_check_init_tracker(pdf_context *ctx, pdfi_check_tracker_t *tracker)
+pdfi_check_init_tracker(pdf_context *ctx, pdfi_check_tracker_t *tracker, pdf_array **fonts_array, pdf_array **spot_array)
{
int code = 0;
@@ -136,16 +140,25 @@ 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->pgs->device->icc_struct->overprint_control) == gs_overprint_control_simulate) {
+ (ctx->pgs->device->icc_struct->overprint_control) == gs_overprint_control_simulate ||
+ spot_array != NULL)
+ {
code = pdfi_dict_alloc(ctx, 32, &tracker->spot_dict);
if (code < 0)
goto cleanup;
pdfi_countup(tracker->spot_dict);
}
+ if (fonts_array != NULL) {
+ code = pdfi_array_alloc(ctx, 0, &tracker->font_array);
+ if (code < 0)
+ goto cleanup;
+ pdfi_countup(tracker->font_array);
+ }
+
return 0;
- cleanup:
+cleanup:
pdfi_check_free_tracker(ctx, tracker);
return code;
}
@@ -164,6 +177,9 @@ static int pdfi_check_ColorSpace_dict(pdf_context *ctx, pdf_dict *cspace_dict,
if (resource_is_checked(tracker, (pdf_obj *)cspace_dict))
return 0;
+ if (pdfi_type_of(cspace_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(cspace_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
if (code < 0)
@@ -197,7 +213,7 @@ static int pdfi_check_ColorSpace_dict(pdf_context *ctx, pdf_dict *cspace_dict,
}
code = pdfi_dict_next(ctx, cspace_dict, &Key, &Value, &index);
- if (code == 0 && Value->type == PDF_ARRAY)
+ if (code == 0 && pdfi_type_of(Value) == PDF_ARRAY)
break;
pdfi_countdown(Key);
Key = NULL;
@@ -235,6 +251,9 @@ static int pdfi_check_Shading(pdf_context *ctx, pdf_obj *shading,
if (code < 0)
return code;
+ if (pdfi_type_of(shading_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
code = pdfi_dict_knownget(ctx, shading_dict, "ColorSpace", (pdf_obj **)&o);
if (code > 0) {
code = pdfi_check_ColorSpace_for_spots(ctx, o, shading_dict, page_dict, tracker->spot_dict);
@@ -257,13 +276,16 @@ static int pdfi_check_Shading_dict(pdf_context *ctx, pdf_dict *shading_dict,
if (resource_is_checked(tracker, (pdf_obj *)shading_dict))
return 0;
+ if (pdfi_type_of(shading_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(shading_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Shading dictionary loop */
if (code < 0)
return code;
code = pdfi_dict_first(ctx, shading_dict, &Key, &Value, &index);
- if (code < 0 || !(Value->type == PDF_DICT || Value->type == PDF_STREAM))
+ if (code < 0 || !(pdfi_type_of(Value) == PDF_DICT || pdfi_type_of(Value) == PDF_STREAM))
goto error1;
i = 1;
@@ -290,7 +312,7 @@ static int pdfi_check_Shading_dict(pdf_context *ctx, pdf_dict *shading_dict,
}
code = pdfi_dict_next(ctx, shading_dict, &Key, &Value, &index);
- if (code == 0 && Value->type == PDF_DICT)
+ if (code == 0 && pdfi_type_of(Value) == PDF_DICT)
break;
pdfi_countdown(Key);
Key = NULL;
@@ -326,6 +348,9 @@ static int pdfi_check_XObject(pdf_context *ctx, pdf_dict *xobject, pdf_dict *pag
if (resource_is_checked(tracker, (pdf_obj *)xobject))
return 0;
+ if (pdfi_type_of(xobject) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
code = pdfi_dict_get_type(ctx, xobject, "Subtype", PDF_NAME, (pdf_obj **)&n);
if (code >= 0) {
if (pdfi_name_is((const pdf_name *)n, "Image")) {
@@ -417,6 +442,9 @@ static int pdfi_check_XObject_dict(pdf_context *ctx, pdf_dict *xobject_dict, pdf
if (resource_is_checked(tracker, (pdf_obj *)xobject_dict))
return 0;
+ if (pdfi_type_of(xobject_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(xobject_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the XObject dictionary loop */
if (code < 0)
@@ -425,7 +453,7 @@ static int pdfi_check_XObject_dict(pdf_context *ctx, pdf_dict *xobject_dict, pdf
code = pdfi_dict_first(ctx, xobject_dict, &Key, &Value, &index);
if (code < 0)
goto error_exit;
- if (Value->type != PDF_STREAM)
+ if (pdfi_type_of(Value) != PDF_STREAM)
goto error_exit;
i = 1;
@@ -457,7 +485,7 @@ static int pdfi_check_XObject_dict(pdf_context *ctx, pdf_dict *xobject_dict, pdf
}
code = pdfi_dict_next(ctx, xobject_dict, &Key, &Value, &index);
- if (code == 0 && Value->type == PDF_STREAM)
+ if (code == 0 && pdfi_type_of(Value) == PDF_STREAM)
break;
pdfi_countdown(Key);
Key = NULL;
@@ -490,6 +518,9 @@ static int pdfi_check_ExtGState(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_
if (resource_is_checked(tracker, (pdf_obj *)extgstate_dict))
return 0;
+ if (pdfi_type_of(extgstate_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(extgstate_dict) > 0) {
/* See if /OP or /op is true */
code = pdfi_dict_get_bool(ctx, extgstate_dict, "OP", &overprint);
@@ -502,14 +533,16 @@ static int pdfi_check_ExtGState(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_
/* Check SMask */
code = pdfi_dict_knownget(ctx, extgstate_dict, "SMask", &o);
if (code > 0) {
- if (o->type == PDF_NAME) {
- if (!pdfi_name_is((pdf_name *)o, "None")) {
- pdfi_countdown(o);
- tracker->transparent = true;
- return 0;
- }
- } else {
- if (o->type == PDF_DICT) {
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ if (!pdfi_name_is((pdf_name *)o, "None")) {
+ pdfi_countdown(o);
+ tracker->transparent = true;
+ return 0;
+ }
+ break;
+ case PDF_DICT:
+ {
pdf_obj *G = NULL;
tracker->transparent = true;
@@ -526,6 +559,8 @@ static int pdfi_check_ExtGState(pdf_context *ctx, pdf_dict *extgstate_dict, pdf_
pdfi_countdown(o);
return code;
}
+ default:
+ break;
}
}
pdfi_countdown(o);
@@ -577,6 +612,9 @@ static int pdfi_check_ExtGState_dict(pdf_context *ctx, pdf_dict *extgstate_dict,
if (resource_is_checked(tracker, (pdf_obj *)extgstate_dict))
return 0;
+ if (pdfi_type_of(extgstate_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(extgstate_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the ColorSpace dictionary loop */
if (code < 0)
@@ -611,7 +649,7 @@ static int pdfi_check_ExtGState_dict(pdf_context *ctx, pdf_dict *extgstate_dict,
}
code = pdfi_dict_next(ctx, extgstate_dict, &Key, &Value, &index);
- if (code == 0 && Value->type == PDF_DICT)
+ if (code == 0 && pdfi_type_of(Value) == PDF_DICT)
break;
pdfi_countdown(Key);
Key = NULL;
@@ -644,6 +682,9 @@ static int pdfi_check_Pattern(pdf_context *ctx, pdf_dict *pattern, pdf_dict *pag
if (resource_is_checked(tracker, (pdf_obj *)pattern))
return 0;
+ if (pdfi_type_of(pattern) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (tracker->spot_dict != NULL) {
code = pdfi_dict_knownget(ctx, pattern, "Shading", &o);
if (code > 0)
@@ -677,7 +718,7 @@ int pdfi_check_Pattern_transparency(pdf_context *ctx, pdf_dict *pattern, pdf_dic
bool *transparent)
{
int code;
- pdfi_check_tracker_t tracker = {0, 0, NULL, 0, NULL};
+ pdfi_check_tracker_t tracker = {0, 0, NULL, NULL, 0, NULL};
/* NOTE: We use a "null" tracker that won't do any optimization to prevent
* checking the same resource twice.
@@ -708,6 +749,9 @@ static int pdfi_check_Pattern_dict(pdf_context *ctx, pdf_dict *pattern_dict, pdf
if (resource_is_checked(tracker, (pdf_obj *)pattern_dict))
return 0;
+ if (pdfi_type_of(pattern_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(pattern_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Pattern dictionary loop */
if (code < 0)
@@ -717,7 +761,7 @@ static int pdfi_check_Pattern_dict(pdf_context *ctx, pdf_dict *pattern_dict, pdf
if (code < 0)
goto error1;
- if(Value->type != PDF_DICT && Value->type != PDF_STREAM)
+ if (pdfi_type_of(Value) != PDF_DICT && pdfi_type_of(Value) != PDF_STREAM)
goto transparency_exit;
i = 1;
@@ -748,7 +792,7 @@ static int pdfi_check_Pattern_dict(pdf_context *ctx, pdf_dict *pattern_dict, pdf
}
code = pdfi_dict_next(ctx, pattern_dict, &Key, &Value, &index);
- if (code == 0 && (Value->type == PDF_DICT || Value->type == PDF_STREAM))
+ if (code == 0 && (pdfi_type_of(Value) == PDF_DICT || pdfi_type_of(Value) == PDF_STREAM))
break;
pdfi_countdown(Key);
Key = NULL;
@@ -771,7 +815,8 @@ error1:
/*
* This routine checks a Font dictionary to see if it contains any spot
- * colour definitions, or transparency usage.
+ * colour definitions, or transparency usage. While we are here, if the tracker's font_array
+ * is not NULL, pick up the font information and store it in the array.
*/
static int pdfi_check_Font(pdf_context *ctx, pdf_dict *font, pdf_dict *page_dict,
pdfi_check_tracker_t *tracker)
@@ -782,22 +827,186 @@ static int pdfi_check_Font(pdf_context *ctx, pdf_dict *font, pdf_dict *page_dict
if (resource_is_checked(tracker, (pdf_obj *)font))
return 0;
- if (font->type != PDF_DICT)
+ if (pdfi_type_of(font) != PDF_DICT)
return_error(gs_error_typecheck);
- code = pdfi_dict_knownget_type(ctx, font, "Subtype", PDF_NAME, &o);
- if (code > 0) {
- if (pdfi_name_is((pdf_name *)o, "Type3")) {
- pdfi_countdown(o);
- o = NULL;
+ if (tracker->font_array != NULL) {
+ /* If we get to here this is a font we have not seen before. We need
+ * to make a new font array big enough to hold the existing entries +1
+ * copy the existing entries to the new array and free the old array.
+ * Finally create a dictionary with all the font information we want
+ * and add it to the array.
+ */
+ pdf_array *new_fonts = NULL;
+ int index = 0;
+ pdf_obj *array_obj = NULL;
+ pdf_dict *font_info_dict = NULL;
- code = pdfi_dict_knownget_type(ctx, font, "Resources", PDF_DICT, &o);
- if (code > 0)
- (void)pdfi_check_Resources(ctx, (pdf_dict *)o, page_dict, tracker);
+ /* Let's start by gathering the information we need and storing it in a dictionary */
+ code = pdfi_dict_alloc(ctx, 4, &font_info_dict);
+ if (code < 0)
+ return code;
+ pdfi_countup(font_info_dict);
+
+ if (font->object_num != 0) {
+ pdf_num *int_obj = NULL;
+
+ code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&int_obj);
+ if (code >= 0) {
+ pdfi_countup(int_obj);
+ int_obj->value.i = font->object_num;
+ code = pdfi_dict_put(ctx, font_info_dict, "ObjectNum", (pdf_obj *)int_obj);
+ pdfi_countdown(int_obj);
+ }
+ if (code < 0) {
+ pdfi_countdown(font_info_dict);
+ return code;
+ }
+ }
+
+ code = pdfi_dict_get(ctx, font, "BaseFont", &array_obj);
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, font_info_dict, "BaseFont", array_obj);
+ if (code < 0) {
+ pdfi_countdown(array_obj);
+ pdfi_countdown(font_info_dict);
+ return code;
+ }
+ }
+ pdfi_countdown(array_obj);
+ array_obj = NULL;
+
+ code = pdfi_dict_get(ctx, font, "ToUnicode", &array_obj);
+ if (code >= 0)
+ code = pdfi_dict_put(ctx, font_info_dict, "ToUnicode", PDF_TRUE_OBJ);
+ else
+ code = pdfi_dict_put(ctx, font_info_dict, "ToUnicode", PDF_FALSE_OBJ);
+ pdfi_countdown(array_obj);
+ array_obj = NULL;
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_get(ctx, font, "FontDescriptor", &array_obj);
+ if (code >= 0) {
+ bool known = false;
+
+ (void)pdfi_dict_known(ctx, (pdf_dict *)array_obj, "FontFile", &known);
+ if (!known) {
+ (void)pdfi_dict_known(ctx, (pdf_dict *)array_obj, "FontFile2", &known);
+ if (!known) {
+ (void)pdfi_dict_known(ctx, (pdf_dict *)array_obj, "FontFile3", &known);
+ }
+ }
+
+ if (known >= 0)
+ code = pdfi_dict_put(ctx, font_info_dict, "Embedded", PDF_TRUE_OBJ);
+ else
+ code = pdfi_dict_put(ctx, font_info_dict, "Embedded", PDF_FALSE_OBJ);
+ } else
+ code = pdfi_dict_put(ctx, font_info_dict, "Embedded", PDF_FALSE_OBJ);
+
+ pdfi_countdown(array_obj);
+ array_obj = NULL;
+
+ if (code < 0)
+ return code;
+
+
+ code = pdfi_dict_knownget_type(ctx, font, "Subtype", PDF_NAME, &array_obj);
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, font_info_dict, "Subtype", array_obj);
+ if (code < 0) {
+ pdfi_countdown(array_obj);
+ pdfi_countdown(font_info_dict);
+ return code;
+ }
+
+ if (pdfi_name_is((pdf_name *)array_obj, "Type3")) {
+ pdfi_countdown(o);
+ o = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, font, "Resources", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_Resources(ctx, (pdf_dict *)o, page_dict, tracker);
+ }
+
+ if (pdfi_name_is((const pdf_name *)array_obj, "Type0")){
+ pdf_array *descendants = NULL;
+ pdf_dict *desc_font = NULL;
+
+ code = pdfi_dict_get(ctx, font, "DescendantFonts", (pdf_obj **)&descendants);
+ if (code >= 0) {
+ code = pdfi_array_get(ctx, descendants, 0, (pdf_obj **)&desc_font);
+ if (code >= 0){
+ pdf_array *desc_array = NULL;
+
+ code = pdfi_array_alloc(ctx, 0, &desc_array);
+ pdfi_countup(desc_array);
+ if (code >= 0) {
+ pdf_array *saved = tracker->font_array;
+
+ tracker->font_array = desc_array;
+ (void)pdfi_check_Font(ctx, desc_font, page_dict, tracker);
+ (void)pdfi_dict_put(ctx, font_info_dict, "Descendants", (pdf_obj *)tracker->font_array);
+ pdfi_countdown((pdf_obj *)tracker->font_array);
+ tracker->font_array = saved;
+ }
+ pdfi_countdown(descendants);
+ pdfi_countdown(desc_font);
+ }
+ }
+ }
+ }
+ pdfi_countdown(array_obj);
+ array_obj = NULL;
+
+ code = pdfi_array_alloc(ctx, pdfi_array_size(tracker->font_array) + 1, &new_fonts);
+ if (code < 0) {
+ pdfi_countdown(font_info_dict);
+ return code;
+ }
+ pdfi_countup(new_fonts);
+
+ for (index = 0; index < pdfi_array_size(tracker->font_array); index++) {
+ code = pdfi_array_get(ctx, tracker->font_array, index, &array_obj);
+ if (code < 0) {
+ pdfi_countdown(font_info_dict);
+ pdfi_countdown(new_fonts);
+ return code;
+ }
+ code = pdfi_array_put(ctx, new_fonts, index, array_obj);
+ pdfi_countdown(array_obj);
+ if (code < 0) {
+ pdfi_countdown(font_info_dict);
+ pdfi_countdown(new_fonts);
+ return code;
+ }
+ }
+ code = pdfi_array_put(ctx, new_fonts, index, (pdf_obj *)font_info_dict);
+ if (code < 0) {
+ pdfi_countdown(font_info_dict);
+ pdfi_countdown(new_fonts);
+ return code;
}
+ pdfi_countdown(font_info_dict);
+ pdfi_countdown(tracker->font_array);
+ tracker->font_array = new_fonts;
+ } else {
+ code = pdfi_dict_knownget_type(ctx, font, "Subtype", PDF_NAME, &o);
+ if (code > 0) {
+ if (pdfi_name_is((pdf_name *)o, "Type3")) {
+ pdfi_countdown(o);
+ o = NULL;
+
+ code = pdfi_dict_knownget_type(ctx, font, "Resources", PDF_DICT, &o);
+ if (code > 0)
+ (void)pdfi_check_Resources(ctx, (pdf_dict *)o, page_dict, tracker);
+ }
+ }
+
+ pdfi_countdown(o);
+ o = NULL;
}
- pdfi_countdown(o);
- o = NULL;
return 0;
}
@@ -815,6 +1024,9 @@ static int pdfi_check_Font_dict(pdf_context *ctx, pdf_dict *font_dict, pdf_dict
if (resource_is_checked(tracker, (pdf_obj *)font_dict))
return 0;
+ if (pdfi_type_of(font_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
if (pdfi_dict_entries(font_dict) > 0) {
code = pdfi_loop_detector_mark(ctx); /* Mark the start of the Font dictionary loop */
if (code < 0)
@@ -846,7 +1058,7 @@ static int pdfi_check_Font_dict(pdf_context *ctx, pdf_dict *font_dict, pdf_dict
}
code = pdfi_dict_next(ctx, font_dict, &Key, &Value, &index);
- if (code == 0 && Value->type == PDF_DICT)
+ if (code == 0 && pdfi_type_of(Value) == PDF_DICT)
break;
pdfi_countdown(Key);
Key = NULL;
@@ -875,6 +1087,9 @@ static int pdfi_check_Resources(pdf_context *ctx, pdf_dict *Resources_dict,
if (resource_is_checked(tracker, (pdf_obj *)Resources_dict))
return 0;
+ if (pdfi_type_of(Resources_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
/* First up, check any colour spaces, for new spot colours.
* We only do this if asked because its expensive. spot_dict being NULL
* means we aren't interested in spot colours (not a DeviceN or Separation device)
@@ -937,6 +1152,9 @@ static int pdfi_check_annot_for_transparency(pdf_context *ctx, pdf_dict *annot,
if (resource_is_checked(tracker, (pdf_obj *)annot))
return 0;
+ if (pdfi_type_of(annot) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
/* Check #1 Does the (Normal) Appearnce stream use any Resources which include transparency.
* We check this first, because this also checks for spot colour spaces. Once we've done that we
* can exit the checks as soon as we detect transparency.
@@ -1035,6 +1253,9 @@ static int pdfi_check_Annots_for_transparency(pdf_context *ctx, pdf_array *annot
if (resource_is_checked(tracker, (pdf_obj *)annots_array))
return 0;
+ if (pdfi_type_of(annots_array) != PDF_ARRAY)
+ return_error(gs_error_typecheck);
+
for (i=0; i < pdfi_array_size(annots_array); i++) {
code = pdfi_array_get_type(ctx, annots_array, (uint64_t)i, PDF_DICT, (pdf_obj **)&annot);
if (code >= 0) {
@@ -1084,6 +1305,10 @@ static int pdfi_check_page_inner(pdf_context *ctx, pdf_dict *page_dict,
tracker->transparent = false;
+ if (pdfi_type_of(page_dict) != PDF_DICT)
+ return_error(gs_error_typecheck);
+
+
/* Check if the page dictionary has a page Group entry (for spots).
* Page group should mean the page has transparency but we ignore it for the purposes
* of transparency detection. See above.
@@ -1104,7 +1329,7 @@ static int pdfi_check_page_inner(pdf_context *ctx, pdf_dict *page_dict,
code = pdfi_dict_knownget_type(ctx, page_dict, "Resources", PDF_DICT, (pdf_obj **)&Resources);
if (code > 0)
code = pdfi_check_Resources(ctx, Resources, page_dict, tracker);
- if ((code < 0 && ctx->args.pdfstoponerror) || (code == gs_error_stackoverflow))
+ if ((code < 0 && ctx->args.pdfstoponerror) || (code == gs_error_pdf_stackoverflow))
goto exit;
/* If we are drawing Annotations, check to see if the page uses any Annots */
@@ -1130,7 +1355,7 @@ static int pdfi_check_page_inner(pdf_context *ctx, pdf_dict *page_dict,
* Sets ctx->page.has_transparency and ctx->page.num_spots
* do_setup -- indicates whether to actually set up the device with the spot count.
*/
-int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
+int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, pdf_array **fonts_array, pdf_array **spots_array, bool do_setup)
{
int code;
int spots = 0;
@@ -1145,7 +1370,7 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
* TODO: Should probably look into that..
*/
pdfi_device_set_flags(ctx);
- code = pdfi_check_init_tracker(ctx, &tracker);
+ code = pdfi_check_init_tracker(ctx, &tracker, fonts_array, spots_array);
if (code < 0)
goto exit;
@@ -1191,7 +1416,7 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
code = pdfi_dict_first(ctx, tracker.spot_dict, (pdf_obj **)&Key, &Value, &index);
while (code >= 0)
{
- if (Key->type == PDF_NAME) {
+ if (pdfi_type_of(Key) == PDF_NAME) {
table[a].data = ((pdf_string *)Key)->data;
table[a].size = ((pdf_string *)Key)->length;
table[a++].persistent = false;
@@ -1263,6 +1488,47 @@ int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup)
ctx->page.has_OP = false;
exit:
+ if (fonts_array != NULL) {
+ *fonts_array = tracker.font_array;
+ pdfi_countup(*fonts_array);
+ }
+
+ if (spots_array != NULL && tracker.spot_dict != NULL && pdfi_dict_entries(tracker.spot_dict) != 0) {
+ pdf_array *new_array = NULL;
+ pdf_name *Key = NULL;
+ pdf_obj *Value = NULL;
+ uint64_t index = 0, a_index = 0;
+
+ index = pdfi_dict_entries(tracker.spot_dict);
+
+ code = pdfi_array_alloc(ctx, index, &new_array);
+ if (code < 0)
+ goto error;
+ pdfi_countup(new_array);
+
+ code = pdfi_dict_first(ctx, tracker.spot_dict, (pdf_obj **)&Key, &Value, &index);
+ while (code >= 0)
+ {
+ if (pdfi_type_of(Key) == PDF_NAME) {
+ code = pdfi_array_put(ctx, new_array, a_index++, (pdf_obj *)Key);
+ if (code < 0) {
+ pdfi_countdown(new_array);
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+ goto error;
+ }
+ }
+
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+ code = pdfi_dict_next(ctx, tracker.spot_dict, (pdf_obj **)&Key, &Value, &index);
+ }
+ code = 0;
+ *spots_array = new_array;
+ }
+error:
(void)pdfi_check_free_tracker(ctx, &tracker);
return code;
}
diff --git a/pdf/pdf_check.h b/pdf/pdf_check.h
index eee5c82b..68619864 100644
--- a/pdf/pdf_check.h
+++ b/pdf/pdf_check.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
@@ -16,7 +16,7 @@
#ifndef PDF_CHECK
#define PDF_CHECK
-int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, bool do_setup);
+int pdfi_check_page(pdf_context *ctx, pdf_dict *page_dict, pdf_array **fonts_array, pdf_array **spots_array, bool do_setup);
int pdfi_check_Pattern_transparency(pdf_context *ctx, pdf_dict *pattern,
pdf_dict *page_dict, bool *transparent);
diff --git a/pdf/pdf_cmap.c b/pdf/pdf_cmap.c
index d7198e24..792b8d1b 100644
--- a/pdf/pdf_cmap.c
+++ b/pdf/pdf_cmap.c
@@ -790,17 +790,20 @@ pdfi_read_cmap(pdf_context *ctx, pdf_obj *cmap, pdf_cmap **pcmap)
pdf_ps_ctx_t cmap_ctx;
pdfi_cmap->ctx = ctx;
- if (cmap->type == PDF_NAME) {
- gs_string cmname;
- pdf_name *cmapn = (pdf_name *)cmap;
- cmname.data = cmapn->data;
- cmname.size = cmapn->length;
- code = pdf_cmap_open_file(ctx, &cmname, &buf, &buflen);
- if (code < 0)
- goto error_out;
- }
- else {
- if (cmap->type == PDF_STREAM) {
+ switch (pdfi_type_of(cmap)) {
+ case PDF_NAME:
+ {
+ gs_string cmname;
+ pdf_name *cmapn = (pdf_name *)cmap;
+ cmname.data = cmapn->data;
+ cmname.size = cmapn->length;
+ code = pdf_cmap_open_file(ctx, &cmname, &buf, &buflen);
+ if (code < 0)
+ goto error_out;
+ break;
+ }
+ case PDF_STREAM:
+ {
pdf_obj *ucmap;
pdf_cmap *upcmap = NULL;
pdf_dict *cmap_dict = NULL;
@@ -842,11 +845,11 @@ pdfi_read_cmap(pdf_context *ctx, pdf_obj *cmap, pdf_cmap **pcmap)
if (code < 0) {
goto error_out;
}
+ break;
}
- else {
- code = gs_note_error(gs_error_typecheck);
- goto error_out;
- }
+ default:
+ code = gs_note_error(gs_error_typecheck);
+ goto error_out;
}
pdfi_cmap->ctx = ctx;
pdfi_cmap->buf = buf;
diff --git a/pdf/pdf_colour.c b/pdf/pdf_colour.c
index dcc3ebf0..0fad43a6 100644
--- a/pdf/pdf_colour.c
+++ b/pdf/pdf_colour.c
@@ -227,7 +227,7 @@ static int pdfi_check_for_spots_by_array(pdf_context *ctx, pdf_array *color_arra
if (code < 0)
goto exit;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -256,15 +256,16 @@ int pdfi_check_ColorSpace_for_spots(pdf_context *ctx, pdf_obj *space, pdf_dict *
if (code < 0)
return code;
- if (space->type == PDF_NAME) {
- code = pdfi_check_for_spots_by_name(ctx, (pdf_name *)space, parent_dict, page_dict, spot_dict);
- } else {
- if (space->type == PDF_ARRAY) {
+ switch(pdfi_type_of(space)) {
+ case PDF_NAME:
+ code = pdfi_check_for_spots_by_name(ctx, (pdf_name *)space, parent_dict, page_dict, spot_dict);
+ break;
+ case PDF_ARRAY:
code = pdfi_check_for_spots_by_array(ctx, (pdf_array *)space, parent_dict, page_dict, spot_dict);
- } else {
+ break;
+ default:
pdfi_loop_detector_cleartomark(ctx);
return 0;
- }
}
(void)pdfi_loop_detector_cleartomark(ctx);
@@ -282,13 +283,15 @@ int pdfi_ri(pdf_context *ctx)
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- if (ctx->stack_top[-1]->type != PDF_NAME) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_NAME) {
pdfi_pop(ctx, 1);
return_error(gs_error_typecheck);
}
n = (pdf_name *)ctx->stack_top[-1];
- code = pdfi_setrenderingintent(ctx, n);
+ pdfi_countup(n);
pdfi_pop(ctx, 1);
+ code = pdfi_setrenderingintent(ctx, n);
+ pdfi_countdown(n);
return code;
}
@@ -330,7 +333,7 @@ static void pdfi_cspace_free_callback(gs_memory_t * mem, void *cs)
if (pfn)
pdfi_free_function(ctx, pfn);
}
- if (o->type != PDF_CTX) {
+ if (pdfi_type_of(o) != PDF_CTX) {
pdfi_countdown(o);
pcs->interpreter_data = NULL;
}
@@ -439,84 +442,45 @@ int pdfi_gs_setcolorspace(pdf_context *ctx, gs_color_space *pcs)
/* Start with the simple cases, where we set the colour space and colour in a single operation */
int pdfi_setgraystroke(pdf_context *ctx)
{
- pdf_num *n1;
int code;
double d1;
- if (pdfi_count_stack(ctx) < 1)
- return_error(gs_error_stackunderflow);
+ code = pdfi_destack_real(ctx, &d1);
+ if (code < 0)
+ return code;
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- d1 = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- d1 = n1->value.d;
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
gs_swapcolors_quick(ctx->pgs);
code = pdfi_gs_setgray(ctx, d1);
gs_swapcolors_quick(ctx->pgs);
- pdfi_pop(ctx, 1);
+
return code;
}
int pdfi_setgrayfill(pdf_context *ctx)
{
- pdf_num *n1;
int code;
double d1;
- if (pdfi_count_stack(ctx) < 1)
- return_error(gs_error_stackunderflow);
+ code = pdfi_destack_real(ctx, &d1);
+ if (code < 0)
+ return code;
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- d1 = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- d1 = n1->value.d;
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
- code = pdfi_gs_setgray(ctx, d1);
- pdfi_pop(ctx, 1);
- return code;
+ return pdfi_gs_setgray(ctx, d1);
}
int pdfi_setrgbstroke(pdf_context *ctx)
{
- pdf_num *num;
double Values[3];
- int i, code;
+ int code;
- if (pdfi_count_stack(ctx) < 3) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ code = pdfi_destack_reals(ctx, Values, 3);
+ if (code < 0)
+ return code;
- for (i=0;i < 3;i++){
- num = (pdf_num *)ctx->stack_top[i - 3];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 3);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
gs_swapcolors_quick(ctx->pgs);
code = pdfi_gs_setrgbcolor(ctx, Values[0], Values[1], Values[2]);
gs_swapcolors_quick(ctx->pgs);
- pdfi_pop(ctx, 3);
+
return code;
}
@@ -534,104 +498,57 @@ int pdfi_setrgbfill_array(pdf_context *ctx)
return_error(gs_error_stackunderflow);
array = (pdf_array *)ctx->stack_top[-1];
- if (array->type != PDF_ARRAY) {
+ pdfi_countup(array);
+ pdfi_pop(ctx, 1);
+ if (pdfi_type_of(array) != PDF_ARRAY) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
code = pdfi_setcolor_from_array(ctx, array);
exit:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(array);
return code;
}
int pdfi_setrgbfill(pdf_context *ctx)
{
- pdf_num *num;
double Values[3];
- int i, code;
+ int code;
- if (pdfi_count_stack(ctx) < 3) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ code = pdfi_destack_reals(ctx, Values, 3);
+ if (code < 0)
+ return code;
- for (i=0;i < 3;i++){
- num = (pdf_num *)ctx->stack_top[i - 3];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 3);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
- code = pdfi_gs_setrgbcolor(ctx, Values[0], Values[1], Values[2]);
- pdfi_pop(ctx, 3);
- return code;
+ return pdfi_gs_setrgbcolor(ctx, Values[0], Values[1], Values[2]);
}
int pdfi_setcmykstroke(pdf_context *ctx)
{
- pdf_num *num;
double Values[4];
- int i, code;
+ int code;
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
gs_swapcolors_quick(ctx->pgs);
code = pdfi_gs_setcmykcolor(ctx, Values[0], Values[1], Values[2], Values[3]);
gs_swapcolors_quick(ctx->pgs);
- pdfi_pop(ctx, 4);
+
return code;
}
int pdfi_setcmykfill(pdf_context *ctx)
{
- pdf_num *num;
double Values[4];
- int i, code;
+ int code;
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
- code = pdfi_gs_setcmykcolor(ctx, Values[0], Values[1], Values[2], Values[3]);
- pdfi_pop(ctx, 4);
- return code;
+ return pdfi_gs_setcmykcolor(ctx, Values[0], Values[1], Values[2], Values[3]);
}
/* Do a setcolor using values in an array
@@ -675,27 +592,22 @@ int pdfi_setcolor_from_array(pdf_context *ctx, pdf_array *array)
static int
pdfi_get_color_from_stack(pdf_context *ctx, gs_client_color *cc, int ncomps)
{
- int i;
- pdf_num *n;
+ int i, code;
if (pdfi_count_stack(ctx) < ncomps) {
pdfi_clearstack(ctx);
return_error(gs_error_stackunderflow);
}
- for (i=0;i<ncomps;i++){
- n = (pdf_num *)ctx->stack_top[i - ncomps];
- if (n->type == PDF_INT) {
- cc->paint.values[i] = (float)n->value.i;
- } else {
- if (n->type == PDF_REAL) {
- cc->paint.values[i] = n->value.d;
- } else {
- pdfi_clearstack(ctx);
- return_error(gs_error_typecheck);
- }
+
+ for (i = 0; i < ncomps; i++) {
+ code = pdfi_obj_to_float(ctx, ctx->stack_top[i - ncomps], &cc->paint.values[i]);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
}
}
pdfi_pop(ctx, ncomps);
+
return 0;
}
@@ -780,14 +692,20 @@ pdfi_setcolorN(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, boo
if (pcs->type == &gs_color_space_type_Pattern)
is_pattern = true;
if (is_pattern) {
- if (ctx->stack_top[-1]->type != PDF_NAME) {
+ pdf_name *n = NULL;
+
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_NAME) {
pdfi_clearstack(ctx);
- code = gs_note_error(gs_error_syntaxerror);
+ code = gs_note_error(gs_error_typecheck);
goto cleanupExit0;
}
- base_space = pcs->base_space;
- code = pdfi_pattern_set(ctx, stream_dict, page_dict, (pdf_name *)ctx->stack_top[-1], &cc);
+ n = (pdf_name *)ctx->stack_top[-1];
+ pdfi_countup(n);
pdfi_pop(ctx, 1);
+
+ base_space = pcs->base_space;
+ code = pdfi_pattern_set(ctx, stream_dict, page_dict, n, &cc);
+ pdfi_countdown(n);
if (code < 0) {
/* 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");
@@ -1125,14 +1043,19 @@ static int pdfi_create_iccbased(pdf_context *ctx, pdf_array *color_array, int in
}
code = pdfi_dict_knownget(ctx, dict, "Name", &Name);
if (code > 0) {
- if(Name->type == PDF_STRING || Name->type == PDF_NAME) {
- cname = (char *)gs_alloc_bytes(ctx->memory, ((pdf_name *)Name)->length + 1, "pdfi_create_iccbased (profile name)");
- if (cname == NULL) {
- code = gs_note_error(gs_error_VMerror);
- goto done;
- }
- memset(cname, 0x00, ((pdf_name *)Name)->length + 1);
- memcpy(cname, ((pdf_name *)Name)->data, ((pdf_name *)Name)->length);
+ switch (pdfi_type_of(Name)) {
+ case PDF_STRING:
+ case PDF_NAME:
+ cname = (char *)gs_alloc_bytes(ctx->memory, ((pdf_name *)Name)->length + 1, "pdfi_create_iccbased (profile name)");
+ if (cname == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto done;
+ }
+ memset(cname, 0x00, ((pdf_name *)Name)->length + 1);
+ memcpy(cname, ((pdf_name *)Name)->data, ((pdf_name *)Name)->length);
+ break;
+ default:
+ break;
}
}
if (code < 0)
@@ -1146,7 +1069,7 @@ static int pdfi_create_iccbased(pdf_context *ctx, pdf_array *color_array, int in
int i;
if (pdfi_array_size(a) >= N * 2) {
- for (i = 0; i < pdfi_array_size(a);i++) {
+ for (i = 0; i < N * 2;i++) {
code = pdfi_array_get_number(ctx, a, i, &dbl);
if (code < 0) {
known = false;
@@ -1218,7 +1141,7 @@ static int pdfi_create_iccbased(pdf_context *ctx, pdf_array *color_array, int in
code = pdfi_dict_knownget(ctx, dict, "Alternate", &Alternate);
if (code > 0) {
/* The Alternate should be one of the device spaces, therefore a Name object. If its not, fallback to using /N */
- if (Alternate->type == PDF_NAME)
+ if (pdfi_type_of(Alternate) == PDF_NAME)
code = pdfi_create_colorspace_by_name(ctx, (pdf_name *)Alternate, stream_dict,
page_dict, ppcs, inline_image);
pdfi_countdown(Alternate);
@@ -1639,23 +1562,23 @@ static int pdfi_create_Separation(pdf_context *ctx, pdf_array *color_array, int
if (code < 0)
goto pdfi_separation_error;
- if (o->type == PDF_NAME) {
- NamedAlternate = (pdf_name *)o;
- code = pdfi_create_colorspace_by_name(ctx, NamedAlternate, stream_dict, page_dict, &pcs_alt, inline_image);
- if (code < 0)
- goto pdfi_separation_error;
-
- } else {
- if (o->type == PDF_ARRAY) {
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ NamedAlternate = (pdf_name *)o;
+ code = pdfi_create_colorspace_by_name(ctx, NamedAlternate, stream_dict, page_dict, &pcs_alt, inline_image);
+ if (code < 0)
+ goto pdfi_separation_error;
+ break;
+ case 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)
goto pdfi_separation_error;
- }
- else {
+ break;
+ default:
+ pdfi_countdown(o);
code = gs_error_typecheck;
goto pdfi_separation_error;
- }
}
code = pdfi_array_get(ctx, color_array, index + 3, &transform);
@@ -1814,14 +1737,14 @@ all_error:
if (code < 0)
goto pdfi_devicen_error;
- if (o->type == PDF_NAME) {
- NamedAlternate = (pdf_name *)o;
- code = pdfi_create_colorspace_by_name(ctx, NamedAlternate, stream_dict, page_dict, &pcs_alt, inline_image);
- if (code < 0)
- goto pdfi_devicen_error;
-
- } else {
- if (o->type == PDF_ARRAY) {
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ NamedAlternate = (pdf_name *)o;
+ code = pdfi_create_colorspace_by_name(ctx, NamedAlternate, stream_dict, page_dict, &pcs_alt, inline_image);
+ if (code < 0)
+ goto pdfi_devicen_error;
+ break;
+ case 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)
@@ -1830,12 +1753,11 @@ all_error:
* paths count down ArrayAlternate.
*/
goto pdfi_devicen_error;
- }
- else {
+ break;
+ default:
code = gs_error_typecheck;
pdfi_countdown(o);
goto pdfi_devicen_error;
- }
}
/* Now the tint transform */
@@ -1889,21 +1811,24 @@ all_error:
if (code == 0) {
pcs->params.device_n.subtype = gs_devicen_DeviceN;
} else {
- if (subtype->type == PDF_NAME || subtype->type == PDF_STRING) {
- if (memcmp(((pdf_name *)subtype)->data, "DeviceN", 7) == 0) {
- pcs->params.device_n.subtype = gs_devicen_DeviceN;
- } else {
- if (memcmp(((pdf_name *)subtype)->data, "NChannel", 8) == 0) {
- pcs->params.device_n.subtype = gs_devicen_NChannel;
+ switch (pdfi_type_of(subtype)) {
+ case PDF_NAME:
+ case PDF_STRING:
+ if (memcmp(((pdf_name *)subtype)->data, "DeviceN", 7) == 0) {
+ pcs->params.device_n.subtype = gs_devicen_DeviceN;
} else {
- pdfi_countdown(subtype);
- goto pdfi_devicen_error;
+ if (memcmp(((pdf_name *)subtype)->data, "NChannel", 8) == 0) {
+ pcs->params.device_n.subtype = gs_devicen_NChannel;
+ } else {
+ pdfi_countdown(subtype);
+ goto pdfi_devicen_error;
+ }
}
- }
- pdfi_countdown(subtype);
- } else {
- pdfi_countdown(subtype);
- goto pdfi_devicen_error;
+ pdfi_countdown(subtype);
+ break;
+ default:
+ pdfi_countdown(subtype);
+ goto pdfi_devicen_error;
}
}
@@ -1944,21 +1869,24 @@ all_error:
goto pdfi_devicen_error;
}
- if (name->type == PDF_NAME || name->type == PDF_STRING) {
- pcs->params.device_n.process_names[ix] = (char *)gs_alloc_bytes(pcs->params.device_n.mem->non_gc_memory, ((pdf_name *)name)->length + 1, "pdfi_devicen(Processnames)");
- if (pcs->params.device_n.process_names[ix] == NULL) {
+ switch (pdfi_type_of(name)) {
+ case PDF_NAME:
+ case PDF_STRING:
+ pcs->params.device_n.process_names[ix] = (char *)gs_alloc_bytes(pcs->params.device_n.mem->non_gc_memory, ((pdf_name *)name)->length + 1, "pdfi_devicen(Processnames)");
+ if (pcs->params.device_n.process_names[ix] == NULL) {
+ pdfi_countdown(Components);
+ pdfi_countdown(name);
+ code = gs_error_VMerror;
+ goto pdfi_devicen_error;
+ }
+ memcpy(pcs->params.device_n.process_names[ix], ((pdf_name *)name)->data, ((pdf_name *)name)->length);
+ pcs->params.device_n.process_names[ix][((pdf_name *)name)->length] = 0x00;
+ pdfi_countdown(name);
+ break;
+ default:
pdfi_countdown(Components);
pdfi_countdown(name);
- code = gs_error_VMerror;
goto pdfi_devicen_error;
- }
- memcpy(pcs->params.device_n.process_names[ix], ((pdf_name *)name)->data, ((pdf_name *)name)->length);
- pcs->params.device_n.process_names[ix][((pdf_name *)name)->length] = 0x00;
- pdfi_countdown(name);
- } else {
- pdfi_countdown(Components);
- pdfi_countdown(name);
- goto pdfi_devicen_error;
}
}
pdfi_countdown(Components);
@@ -1979,17 +1907,26 @@ all_error:
goto pdfi_devicen_error;
do {
- if (Space->type != PDF_STRING && Space->type != PDF_NAME && Space->type != PDF_ARRAY) {
- pdfi_countdown(Space);
- pdfi_countdown(Colorant);
- code = gs_note_error(gs_error_typecheck);
- goto pdfi_devicen_error;
+ switch (pdfi_type_of(Space)) {
+ case PDF_STRING:
+ case PDF_NAME:
+ case PDF_ARRAY:
+ break;
+ default:
+ pdfi_countdown(Space);
+ pdfi_countdown(Colorant);
+ code = gs_note_error(gs_error_typecheck);
+ goto pdfi_devicen_error;
}
- if (Colorant->type != PDF_STRING && Colorant->type != PDF_NAME) {
- pdfi_countdown(Space);
- pdfi_countdown(Colorant);
- code = gs_note_error(gs_error_typecheck);
- goto pdfi_devicen_error;
+ switch (pdfi_type_of(Colorant)) {
+ case PDF_STRING:
+ case PDF_NAME:
+ break;
+ default:
+ pdfi_countdown(Space);
+ pdfi_countdown(Colorant);
+ code = gs_note_error(gs_error_typecheck);
+ goto pdfi_devicen_error;
}
code = pdfi_create_colorspace(ctx, Space, stream_dict, page_dict, &colorant_space, inline_image);
@@ -2115,11 +2052,14 @@ pdfi_create_indexed(pdf_context *ctx, pdf_array *color_array, int index,
if (code < 0)
goto exit;
- if (lookup->type == PDF_STREAM) {
+ switch (pdfi_type_of(lookup)) {
+ case PDF_STREAM:
code = pdfi_stream_to_buffer(ctx, (pdf_stream *)lookup, &Buffer, &lookup_length);
if (code < 0)
goto exit;
- } else if (lookup->type == PDF_STRING) {
+ break;
+ case PDF_STRING:
+ {
/* This is not legal, but Acrobat seems to accept it */
pdf_string *lookup_string = (pdf_string *)lookup; /* alias */
@@ -2131,7 +2071,9 @@ pdfi_create_indexed(pdf_context *ctx, pdf_array *color_array, int index,
memcpy(Buffer, lookup_string->data, lookup_string->length);
lookup_length = lookup_string->length;
- } else {
+ break;
+ }
+ default:
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -2208,6 +2150,7 @@ static int pdfi_create_DeviceGray(pdf_context *ctx, gs_color_space **ppcs)
}
} else {
code = pdfi_gs_setgray(ctx, 0);
+ pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
}
return code;
}
@@ -2236,6 +2179,7 @@ static int pdfi_create_DeviceRGB(pdf_context *ctx, gs_color_space **ppcs)
}
} else {
code = pdfi_gs_setrgbcolor(ctx, 0, 0, 0);
+ pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
}
return code;
}
@@ -2264,6 +2208,7 @@ static int pdfi_create_DeviceCMYK(pdf_context *ctx, gs_color_space **ppcs)
}
} else {
code = pdfi_gs_setcmykcolor(ctx, 0, 0, 0, 1);
+ pdfi_set_colour_callback(ctx->pgs->color[0].color_space, ctx, pdfi_cspace_free_callback);
}
return code;
}
@@ -2352,7 +2297,7 @@ pdfi_create_colorspace_by_array(pdf_context *ctx, pdf_array *color_array, int in
if (code < 0)
goto exit;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -2416,11 +2361,15 @@ pdfi_create_colorspace_by_name(pdf_context *ctx, pdf_name *name,
if (code < 0)
return code;
- if (ref_space->type == PDF_NAME) {
+ if (pdfi_type_of(ref_space) == 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);
}
+ if (((pdf_name *)ref_space)->length <= 0) {
+ pdfi_countdown(ref_space);
+ return_error(gs_error_syntaxerror);
+ }
}
/* recursion */
@@ -2492,15 +2441,16 @@ int pdfi_create_colorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_di
if (code < 0)
return code;
- if (space->type == PDF_NAME) {
+ switch (pdfi_type_of(space)) {
+ case PDF_NAME:
code = pdfi_create_colorspace_by_name(ctx, (pdf_name *)space, stream_dict, page_dict, ppcs, inline_image);
- } else {
- if (space->type == PDF_ARRAY) {
- code = pdfi_create_colorspace_by_array(ctx, (pdf_array *)space, 0, stream_dict, page_dict, ppcs, inline_image);
- } else {
- pdfi_loop_detector_cleartomark(ctx);
- return_error(gs_error_typecheck);
- }
+ break;
+ case PDF_ARRAY:
+ code = pdfi_create_colorspace_by_array(ctx, (pdf_array *)space, 0, stream_dict, page_dict, ppcs, inline_image);
+ break;
+ default:
+ pdfi_loop_detector_cleartomark(ctx);
+ return_error(gs_error_typecheck);
}
if (code >= 0 && ppcs && *ppcs)
(void)(*ppcs)->type->install_cspace(*ppcs, ctx->pgs);
@@ -2518,36 +2468,46 @@ int pdfi_setcolorspace(pdf_context *ctx, pdf_obj *space, pdf_dict *stream_dict,
int pdfi_setstrokecolor_space(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
{
int code;
+ pdf_obj *n = NULL;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- if (ctx->stack_top[-1]->type != PDF_NAME) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_NAME) {
pdfi_pop(ctx, 1);
- return_error(gs_error_stackunderflow);
+ return_error(gs_error_typecheck);
}
+ n = ctx->stack_top[-1];
+ pdfi_countup(n);
+ pdfi_pop(ctx, 1);
+
gs_swapcolors_quick(ctx->pgs);
- code = pdfi_setcolorspace(ctx, ctx->stack_top[-1], stream_dict, page_dict);
+ code = pdfi_setcolorspace(ctx, n, stream_dict, page_dict);
gs_swapcolors_quick(ctx->pgs);
- pdfi_pop(ctx, 1);
+ pdfi_countdown(n);
return code;
}
int pdfi_setfillcolor_space(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
{
int code;
+ pdf_obj *n = NULL;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- if (ctx->stack_top[-1]->type != PDF_NAME) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_NAME) {
pdfi_pop(ctx, 1);
- return_error(gs_error_stackunderflow);
+ return_error(gs_error_typecheck);
}
- code = pdfi_setcolorspace(ctx, ctx->stack_top[-1], stream_dict, page_dict);
+ n = ctx->stack_top[-1];
+ pdfi_countup(n);
pdfi_pop(ctx, 1);
+ code = pdfi_setcolorspace(ctx, n, stream_dict, page_dict);
+
+ pdfi_countdown(n);
return code;
}
@@ -2790,7 +2750,7 @@ static int Check_Default_Space(pdf_context *ctx, pdf_obj *space, pdf_dict *sourc
pdf_obj *ref_space = NULL;
int code = 0;
- if (space->type == PDF_NAME)
+ if (pdfi_type_of(space) == PDF_NAME)
{
if (pdfi_name_is((const pdf_name *)space, "DeviceGray"))
return (num_components == 1 ? 0 : gs_error_rangecheck);
@@ -2804,7 +2764,7 @@ static int Check_Default_Space(pdf_context *ctx, pdf_obj *space, pdf_dict *sourc
if (code < 0)
return code;
- if (ref_space->type == PDF_NAME) {
+ if (pdfi_type_of(ref_space) == 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);
@@ -2827,12 +2787,12 @@ static int Check_Default_Space(pdf_context *ctx, pdf_obj *space, pdf_dict *sourc
space = ref_space;
}
- if (space->type == PDF_ARRAY) {
+ if (pdfi_type_of(space) == PDF_ARRAY) {
code = pdfi_array_get(ctx, (pdf_array *)space, 0, &primary);
if (code < 0)
goto exit;
- if (primary->type == PDF_NAME) {
+ if (pdfi_type_of(primary) == PDF_NAME) {
if (pdfi_name_is((pdf_name *)primary, "Lab")) {
code = gs_note_error(gs_error_typecheck);
goto exit;
diff --git a/pdf/pdf_colour.h b/pdf/pdf_colour.h
index 263c3d9d..b279c2f8 100644
--- a/pdf/pdf_colour.h
+++ b/pdf/pdf_colour.h
@@ -27,7 +27,7 @@ static inline void pdfi_set_colourspace_name(pdf_context *ctx, gs_color_space *p
{
if (pcs->interpreter_data != NULL) {
pdf_obj *o = (pdf_obj *)(pcs->interpreter_data);
- if (o != NULL && o->type == PDF_NAME) {
+ if (o != NULL && pdfi_type_of(o) == PDF_NAME) {
pdfi_countdown(o);
pcs->interpreter_data = NULL;
}
@@ -53,7 +53,7 @@ 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)
+ if (o == NULL || pdfi_type_of(o) != PDF_NAME)
return 0;
if (pdfi_name_cmp(n, (pdf_name *)o) == 0) {
diff --git a/pdf/pdf_deref.c b/pdf/pdf_deref.c
index 91d77f63..d444e0c7 100644
--- a/pdf/pdf_deref.c
+++ b/pdf/pdf_deref.c
@@ -45,6 +45,9 @@ static int pdfi_add_to_cache(pdf_context *ctx, pdf_obj *o)
{
pdf_obj_cache_entry *entry;
+ if (o < PDF_TOKEN_AS_OBJ(TOKEN__LAST_KEY))
+ return 0;
+
if (ctx->xref_table->xref[o->object_num].cache != NULL) {
#if DEBUG_CACHE
dmprintf1(ctx->memory, "Attempting to add object %d to cache when the object is already cached!\n", o->object_num);
@@ -200,7 +203,6 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
{
int code = 0;
int64_t i;
- pdf_keyword *keyword = NULL;
pdf_dict *dict = NULL;
gs_offset_t offset;
pdf_stream *stream_obj = NULL;
@@ -222,14 +224,15 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
return_error(gs_error_stackunderflow);
dict = (pdf_dict *)ctx->stack_top[-1];
- dict->indirect_num = dict->object_num = objnum;
- dict->indirect_gen = dict->generation_num = gen;
- if (dict->type != PDF_DICT) {
+ if (pdfi_type_of(dict) != PDF_DICT) {
pdfi_pop(ctx, 1);
return_error(gs_error_syntaxerror);
}
+ dict->indirect_num = dict->object_num = objnum;
+ dict->indirect_gen = dict->generation_num = gen;
+
/* Convert the dict into a stream */
code = pdfi_obj_dict_to_stream(ctx, dict, &stream_obj, true);
if (code < 0) {
@@ -258,12 +261,16 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
pdfi_countdown(stream_obj); /* get rid of extra ref */
return code;
}
- if (pdfi_loop_detector_check_object(ctx, stream_obj->object_num))
+ if (pdfi_loop_detector_check_object(ctx, stream_obj->object_num)) {
+ pdfi_countdown(stream_obj); /* get rid of extra ref */
+ pdfi_loop_detector_cleartomark(ctx);
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 */
+ pdfi_loop_detector_cleartomark(ctx);
return code;
}
@@ -305,8 +312,8 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
stream_obj->Length = 0;
stream_obj->length_valid = false;
- code = pdfi_read_token(ctx, ctx->main_stream, objnum, gen);
- if (code < 0 || pdfi_count_stack(ctx) < 2) {
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
+ if (code == 0) {
char extra_info[gp_file_name_sizeof];
gs_snprintf(extra_info, sizeof(extra_info), "Failed to find a valid object at end of stream object %u.\n", objnum);
@@ -318,34 +325,27 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
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];
+ } else if (code < 0) {
+ char extra_info[gp_file_name_sizeof];
- 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_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 */
- stream_obj->Length = i;
- stream_obj->length_valid = true;
- }
- }
- pdfi_pop(ctx, 1);
+ 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 if (code != TOKEN_ENDSTREAM) {
+ char extra_info[gp_file_name_sizeof];
+
+ 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 */
+ stream_obj->Length = i;
+ stream_obj->length_valid = true;
}
}
/* If we failed to find a valid object, or the object wasn't a keyword, or the
* keywrod wasn't 'endstream' then the Length is wrong. We need to have the correct
* Length for streams if we have encrypted files, because we must install a
- * SubFileDecode filter iwth a Length (EODString is incompatible with AES encryption)
+ * SubFileDecode filter with a Length (EODString is incompatible with AES encryption)
* Rather than mess about checking for encryption, we'll choose to just correctly
* calculate the Length of all streams. Although this takes time, it will only
* happen for files which are invalid.
@@ -393,7 +393,7 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
return 0;
}
- code = pdfi_read_token(ctx, ctx->main_stream, objnum, gen);
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
if (code < 0) {
pdfi_countdown(stream_obj); /* get rid of extra ref */
if (ctx->args.pdfstoponerror)
@@ -406,14 +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 (code == 0) {
pdfi_countdown(stream_obj); /* get rid of extra ref */
return_error(gs_error_stackunderflow);
}
- if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
+ if (code != TOKEN_ENDOBJ) {
pdfi_countdown(stream_obj); /* get rid of extra ref */
- pdfi_pop(ctx, 1);
if (ctx->args.pdfstoponerror)
return_error(gs_error_typecheck);
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGENDOBJ, "pdfi_read_stream_object", NULL);
@@ -424,12 +423,6 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
}
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);
- return_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
return 0;
}
@@ -440,10 +433,12 @@ static int pdfi_read_stream_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_
*/
int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_offset, uint32_t objnum, uint32_t gen)
{
- int code = 0;
- pdf_keyword *keyword = NULL;
+ int code = 0, initial_depth = 0;
+ pdf_key keyword;
gs_offset_t saved_offset[3];
+ pdf_obj_type type;
+ initial_depth = pdfi_count_stack(ctx);
saved_offset[0] = saved_offset[1] = saved_offset[2] = 0;
code = pdfi_read_token(ctx, s, objnum, gen);
@@ -468,13 +463,16 @@ 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);
+ type = pdfi_type_of(ctx->stack_top[-1]);
+ if (type == PDF_KEYWORD)
+ goto missing_endobj;
+ } while (type != PDF_FAST_KEYWORD);
- keyword = ((pdf_keyword *)ctx->stack_top[-1]);
- if (keyword->key == TOKEN_ENDOBJ) {
+ keyword = (pdf_key)(uintptr_t)(ctx->stack_top[-1]);
+ if (keyword == TOKEN_ENDOBJ) {
pdf_obj *o;
- if (pdfi_count_stack(ctx) < 2) {
+ if (pdfi_count_stack(ctx) - initial_depth < 2) {
pdfi_clearstack(ctx);
return_error(gs_error_stackunderflow);
}
@@ -483,21 +481,23 @@ int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_
pdfi_pop(ctx, 1);
- o->indirect_num = o->object_num = objnum;
- o->indirect_gen = o->generation_num = gen;
+ if (o >= PDF_TOKEN_AS_OBJ(TOKEN__LAST_KEY)) {
+ o->indirect_num = o->object_num = objnum;
+ o->indirect_gen = o->generation_num = gen;
+ }
return code;
}
- if (keyword->key == TOKEN_STREAM) {
+ if (keyword == TOKEN_STREAM) {
pdfi_pop(ctx, 1);
return pdfi_read_stream_object(ctx, s, stream_offset, objnum, gen);
}
- if (keyword->key == TOKEN_OBJ) {
+ if (keyword == TOKEN_OBJ) {
pdf_obj *o;
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGENDOBJ, "pdfi_read_bare_object", NULL);
/* 4 for; the object we want, the object number, generation number and 'obj' keyword */
- if (pdfi_count_stack(ctx) < 4)
+ if (pdfi_count_stack(ctx) - initial_depth < 4)
return_error(gs_error_stackunderflow);
/* If we have that many objects, assume that we can throw away the x y obj and just use the remaining object */
@@ -505,28 +505,33 @@ int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_
pdfi_pop(ctx, 3);
- o->indirect_num = o->object_num = objnum;
- o->indirect_gen = o->generation_num = gen;
+ if (pdfi_type_of(o) != PDF_BOOL && pdfi_type_of(o) != PDF_NULL && pdfi_type_of(o) != PDF_FAST_KEYWORD) {
+ o->indirect_num = o->object_num = objnum;
+ o->indirect_gen = o->generation_num = gen;
+ }
if (saved_offset[0] > 0)
(void)pdfi_seek(ctx, s, saved_offset[0], SEEK_SET);
return 0;
}
+missing_endobj:
/* Assume that any other keyword means a missing 'endobj' */
if (!ctx->args.pdfstoponerror) {
pdf_obj *o;
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGENDOBJ, "pdfi_read_bare_object", NULL);
- if (pdfi_count_stack(ctx) < 2)
+ if (pdfi_count_stack(ctx) - initial_depth < 2)
return_error(gs_error_stackunderflow);
o = ctx->stack_top[-2];
pdfi_pop(ctx, 1);
- o->indirect_num = o->object_num = objnum;
- o->indirect_gen = o->generation_num = gen;
+ if (pdfi_type_of(o) != PDF_BOOL && pdfi_type_of(o) != PDF_NULL && pdfi_type_of(o) != PDF_FAST_KEYWORD) {
+ o->indirect_num = o->object_num = objnum;
+ o->indirect_gen = o->generation_num = gen;
+ }
return code;
}
pdfi_pop(ctx, 2);
@@ -535,60 +540,34 @@ int pdfi_read_bare_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_
static int pdfi_read_object(pdf_context *ctx, pdf_c_stream *s, gs_offset_t stream_offset)
{
- int code = 0, stack_size = pdfi_count_stack(ctx);
- uint64_t objnum = 0, gen = 0;
- pdf_keyword *keyword = NULL;
+ int code = 0;
+ int objnum = 0, gen = 0;
/* An object consists of 'num gen obj' followed by a token, follwed by an endobj
* A stream dictionary might have a 'stream' instead of an 'endobj', in which case we
* want to deal with it specially by getting the Length, jumping to the end and checking
* for an endobj. Or not, possibly, because it would be slow.
*/
- code = pdfi_read_token(ctx, s, 0, 0);
+ code = pdfi_read_bare_int(ctx, s, &objnum);
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) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- objnum = ((pdf_num *)ctx->stack_top[-1])->value.i;
- pdfi_pop(ctx, 1);
-
- code = pdfi_read_token(ctx, s, 0, 0);
+ code = pdfi_read_bare_int(ctx, s, &gen);
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) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- gen = ((pdf_num *)ctx->stack_top[-1])->value.i;
- pdfi_pop(ctx, 1);
-
- code = pdfi_read_token(ctx, s, 0, 0);
+ code = pdfi_read_bare_keyword(ctx, s);
if (code < 0)
return code;
- if (stack_size >= pdfi_count_stack(ctx))
+ if (code == 0)
return gs_note_error(gs_error_ioerror);
- if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- keyword = ((pdf_keyword *)ctx->stack_top[-1]);
- if (keyword->key != TOKEN_OBJ) {
- pdfi_pop(ctx, 1);
+ if (code != TOKEN_OBJ) {
return_error(gs_error_syntaxerror);
}
- pdfi_pop(ctx, 1);
return pdfi_read_bare_object(ctx, s, stream_offset, objnum, gen);
}
@@ -602,13 +581,13 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
pdf_c_stream *SubFile_stream = NULL;
pdf_c_stream *Object_stream = NULL;
int i = 0, object_length = 0;
- int64_t num_entries, found_object;
- int64_t Length;
+ int64_t num_entries;
+ int found_object;
+ int64_t Length, First;
gs_offset_t offset = 0;
pdf_stream *compressed_object = NULL;
pdf_dict *compressed_sdict = NULL; /* alias */
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);
@@ -637,7 +616,7 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
goto exit;
}
- if ((ctx->stack_top[-1])->type != PDF_STREAM) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_STREAM) {
pdfi_pop(ctx, 1);
code = gs_note_error(gs_error_typecheck);
goto exit;
@@ -666,31 +645,70 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
if (code < 0)
return code;
+ if (ctx->loop_detection != NULL) {
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ goto exit;
+ if (compressed_sdict->object_num != 0) {
+ if (pdfi_loop_detector_check_object(ctx, compressed_sdict->object_num)) {
+ code = gs_note_error(gs_error_circular_reference);
+ } else {
+ code = pdfi_loop_detector_add_object(ctx, compressed_sdict->object_num);
+ }
+ if (code < 0) {
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ goto exit;
+ }
+ }
+ }
/* Check its an ObjStm ! */
code = pdfi_dict_get_type(ctx, compressed_sdict, "Type", PDF_NAME, (pdf_obj **)&Type);
- if (code < 0)
+ if (code < 0) {
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
goto exit;
+ }
if (!pdfi_name_is(Type, "ObjStm")){
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
code = gs_note_error(gs_error_syntaxerror);
goto exit;
}
/* Need to check the /N entry to see if the object is actually in this stream! */
code = pdfi_dict_get_int(ctx, compressed_sdict, "N", &num_entries);
- if (code < 0)
+ if (code < 0) {
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
goto exit;
+ }
if (num_entries < 0 || num_entries > ctx->xref_table->xref_size) {
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
code = gs_note_error(gs_error_rangecheck);
goto exit;
}
- code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, compressed_object), SEEK_SET);
- if (code < 0)
+ code = pdfi_dict_get_int(ctx, compressed_sdict, "Length", &Length);
+ if (code < 0) {
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
goto exit;
+ }
- code = pdfi_dict_get_int(ctx, compressed_sdict, "Length", &Length);
+ code = pdfi_dict_get_int(ctx, compressed_sdict, "First", &First);
+ if (code < 0) {
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ goto exit;
+ }
+
+ if (ctx->loop_detection != NULL)
+ (void)pdfi_loop_detector_cleartomark(ctx);
+
+ code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, compressed_object), SEEK_SET);
if (code < 0)
goto exit;
@@ -703,57 +721,86 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
goto exit;
for (i=0;i < num_entries;i++)
- {
- 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);
- pdfi_pop(ctx, 1);
- goto exit;
- }
- found_object = ((pdf_num *)temp_obj)->value.i;
- pdfi_pop(ctx, 1);
- 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);
+ {
+ int new_offset;
+ code = pdfi_read_bare_int(ctx, compressed_stream, &found_object);
+ if (code < 0)
+ goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
+ code = pdfi_read_bare_int(ctx, compressed_stream, &new_offset);
+ if (code < 0)
+ goto exit;
+ if (code == 0) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
+ if (i == entry->u.compressed.object_index) {
+ if (found_object != obj) {
+ code = gs_note_error(gs_error_undefined);
goto exit;
}
- if (i == entry->u.compressed.object_index) {
- if (found_object != obj) {
- pdfi_pop(ctx, 1);
- code = gs_note_error(gs_error_undefined);
- goto exit;
- }
- offset = ((pdf_num *)temp_obj)->value.i;
- }
- if (i == entry->u.compressed.object_index + 1)
- object_length = ((pdf_num *)temp_obj)->value.i - offset;
- pdfi_pop(ctx, 1);
+ offset = new_offset;
+ }
+ if (i == entry->u.compressed.object_index + 1)
+ object_length = new_offset - offset;
+ }
+
+ /* Bug #705259 - The first object need not lie immediately after the initial
+ * table of object numbers and offsets. The start of the first object is given
+ * by the value of First. We don't know how many bytes we consumed getting to
+ * the end of the table, unfortunately, so we close the stream, rewind the main
+ * stream back to the beginning of the ObjStm, and then read and discard 'First'
+ * bytes in order to get to the start of the first object. Then we read the
+ * number of bytes required to get from there to the start of the object we
+ * actually want.
+ * If this ever looks like it's causing performance problems we could read the
+ * initial table above manually instead of using the existing code, and track
+ * how many bytes we'd read, which would avoid us having to tear down and
+ * rebuild the stream.
+ */
+ if (compressed_stream)
+ pdfi_close_file(ctx, compressed_stream);
+ if (SubFile_stream)
+ pdfi_close_file(ctx, SubFile_stream);
+
+ code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, compressed_object), SEEK_SET);
+ if (code < 0)
+ goto exit;
+
+ /* We already dereferenced this above, so we don't need the loop detection checking here */
+ code = pdfi_dict_get_int(ctx, compressed_sdict, "Length", &Length);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_apply_SubFileDecode_filter(ctx, Length, NULL, ctx->main_stream, &SubFile_stream, false);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_filter(ctx, compressed_object, SubFile_stream, &compressed_stream, false);
+ if (code < 0)
+ goto exit;
+
+ for (i=0;i < First;i++)
+ {
+ int c = pdfi_read_byte(ctx, compressed_stream);
+ if (c < 0) {
+ code = gs_note_error(gs_error_ioerror);
+ goto exit;
}
+ }
/* Skip to the offset of the object we want to read */
for (i=0;i < offset;i++)
- {
- int c = pdfi_read_byte(ctx, compressed_stream);
- if (c < 0) {
- code = gs_note_error(gs_error_ioerror);
- goto exit;
- }
+ {
+ int c = pdfi_read_byte(ctx, compressed_stream);
+ if (c < 0) {
+ code = gs_note_error(gs_error_ioerror);
+ goto exit;
}
+ }
/* If object_length is not 0, then we want to apply a SubFileDecode filter to limit
* the number of bytes we read to the declared size of the object (difference between
@@ -777,7 +824,7 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
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) {
+ if (pdfi_type_of(ctx->stack_top[-1]) == PDF_ARRAY_MARK || pdfi_type_of(ctx->stack_top[-1]) == PDF_DICT_MARK) {
int start_depth = pdfi_count_stack(ctx);
/* Need to read all the elements from COS objects */
@@ -793,16 +840,18 @@ static int pdfi_deref_compressed(pdf_context *ctx, uint64_t obj, uint64_t gen, p
code = gs_note_error(gs_error_ioerror);
goto exit;
}
- }while ((ctx->stack_top[-1]->type != PDF_ARRAY && ctx->stack_top[-1]->type != PDF_DICT) || pdfi_count_stack(ctx) > start_depth);
+ } while ((pdfi_type_of(ctx->stack_top[-1]) != PDF_ARRAY && pdfi_type_of(ctx->stack_top[-1]) != PDF_DICT) || pdfi_count_stack(ctx) > start_depth);
}
*object = ctx->stack_top[-1];
/* For compressed objects we don't get a 'obj gen obj' sequence which is what sets
* the object number for uncompressed objects. So we need to do that here.
*/
- (*object)->indirect_num = (*object)->object_num = obj;
- (*object)->indirect_gen = (*object)->generation_num = gen;
- pdfi_countup(*object);
+ if (*object >= PDF_TOKEN_AS_OBJ(TOKEN__LAST_KEY)) {
+ (*object)->indirect_num = (*object)->object_num = obj;
+ (*object)->indirect_gen = (*object)->generation_num = gen;
+ pdfi_countup(*object);
+ }
pdfi_pop(ctx, 1);
if (cache) {
@@ -850,10 +899,15 @@ static int pdfi_dereference_main(pdf_context *ctx, uint64_t obj, uint64_t gen, p
if(ctx->args.pdfstoponerror)
return_error(gs_error_rangecheck);
- code = pdfi_object_alloc(ctx, PDF_NULL, 0, object);
- if (code == 0)
- pdfi_countup(*object);
- return code;
+ code = pdfi_repair_file(ctx);
+ if (code < 0) {
+ *object = PDF_NULL_OBJ;
+ return code;
+ }
+ if (obj >= ctx->xref_table->xref_size) {
+ *object = PDF_NULL_OBJ;
+ return_error(gs_error_rangecheck);
+ }
}
entry = &ctx->xref_table->xref[obj];
@@ -924,11 +978,8 @@ static int pdfi_dereference_main(pdf_context *ctx, uint64_t obj, uint64_t gen, p
int code1 = 0;
if (entry->free) {
dmprintf2(ctx->memory, "Dereference of free object %"PRIu64", next object number as offset failed (code = %d), returning NULL object.\n", entry->object_num, code);
- code = pdfi_object_alloc(ctx, PDF_NULL, 1, object);
- if (code >= 0) {
- pdfi_countup(*object);
- goto free_obj;
- }
+ *object = PDF_NULL_OBJ;
+ goto free_obj;
}
ctx->encryption.decrypt_strings = saved_decrypt_strings;
(void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
@@ -941,10 +992,22 @@ static int pdfi_dereference_main(pdf_context *ctx, uint64_t obj, uint64_t gen, p
return code;
}
- if (pdfi_count_stack(ctx) > 0 && (ctx->stack_top[-1])->object_num == obj) {
+ if (pdfi_count_stack(ctx) > 0 &&
+ (ctx->stack_top[-1] > PDF_TOKEN_AS_OBJ(TOKEN__LAST_KEY) &&
+ (ctx->stack_top[-1])->object_num == obj)) {
*object = ctx->stack_top[-1];
pdfi_countup(*object);
pdfi_pop(ctx, 1);
+ if (pdfi_type_of(*object) == PDF_INDIRECT) {
+ pdf_indirect_ref *iref = (pdf_indirect_ref *)*object;
+
+ if (iref->ref_object_num == obj) {
+ code = gs_note_error(gs_error_circular_reference);
+ pdfi_countdown(*object);
+ *object = NULL;
+ goto error;
+ }
+ }
if (cache) {
code = pdfi_add_to_cache(ctx, *object);
if (code < 0) {
@@ -956,10 +1019,8 @@ static int pdfi_dereference_main(pdf_context *ctx, uint64_t obj, uint64_t gen, p
pdfi_pop(ctx, 1);
if (entry->free) {
dmprintf1(ctx->memory, "Dereference of free object %"PRIu64", next object number as offset failed, returning NULL object.\n", entry->object_num);
- code = pdfi_object_alloc(ctx, PDF_NULL, 1, object);
- if (code >= 0)
- pdfi_countup(*object);
- return code;
+ *object = PDF_NULL_OBJ;
+ return 0;
}
code = gs_note_error(gs_error_undefined);
goto error;
@@ -969,7 +1030,7 @@ free_obj:
(void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
}
- if (ctx->loop_detection && (*object)->object_num != 0) {
+ if (ctx->loop_detection && pdf_object_num(*object) != 0) {
code = pdfi_loop_detector_add_object(ctx, (*object)->object_num);
if (code < 0) {
ctx->encryption.decrypt_strings = saved_decrypt_strings;
@@ -1052,11 +1113,12 @@ static int pdfi_resolve_indirect_array(pdf_context *ctx, pdf_obj *obj, bool recu
code = 0;
} else {
if (code < 0) goto exit;
- /* don't store the object if it's a stream (leave as a ref) */
- if (object->type != PDF_STREAM)
- code = pdfi_array_put(ctx, array, index, object);
if (recurse)
code = pdfi_resolve_indirect_loop_detect(ctx, NULL, object, recurse);
+ if (code < 0) goto exit;
+ /* don't store the object if it's a stream (leave as a ref) */
+ if (pdfi_type_of(object) != PDF_STREAM)
+ code = pdfi_array_put(ctx, array, index, object);
}
if (code < 0) goto exit;
@@ -1107,7 +1169,7 @@ static int pdfi_resolve_indirect_dict(pdf_context *ctx, pdf_obj *obj, bool recur
} else {
if (code < 0) goto exit;
/* don't store the object if it's a stream (leave as a ref) */
- if (Value->type != PDF_STREAM)
+ if (pdfi_type_of(Value) != PDF_STREAM)
pdfi_dict_put_obj(ctx, dict, (pdf_obj *)Key, Value, true);
if (recurse)
code = pdfi_resolve_indirect_loop_detect(ctx, NULL, Value, recurse);
@@ -1130,7 +1192,7 @@ int pdfi_resolve_indirect(pdf_context *ctx, pdf_obj *value, bool recurse)
{
int code = 0;
- switch(value->type) {
+ switch(pdfi_type_of(value)) {
case PDF_ARRAY:
code = pdfi_resolve_indirect_array(ctx, value, recurse);
break;
@@ -1158,7 +1220,7 @@ int pdfi_resolve_indirect_loop_detect(pdf_context *ctx, pdf_obj *parent, pdf_obj
if (code < 0) goto exit;
}
- if (value->object_num != 0) {
+ if (pdf_object_num(value) != 0) {
if (pdfi_loop_detector_check_object(ctx, value->object_num)) {
code = gs_note_error(gs_error_circular_reference);
goto exit;
diff --git a/pdf/pdf_dict.c b/pdf/pdf_dict.c
index 34356dfe..217cb6db 100644
--- a/pdf/pdf_dict.c
+++ b/pdf/pdf_dict.c
@@ -140,7 +140,7 @@ int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indir
i = (index / 2) - 1;
/* 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) {
+ if (pdfi_type_of((pdf_obj *)ctx->stack_top[-2]) == PDF_NAME) {
d->list[i].key = ctx->stack_top[-2];
pdfi_countup(d->list[i].key);
#if DEBUG_DICT
@@ -149,7 +149,7 @@ int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indir
d->list[i].value = ctx->stack_top[-1];
pdfi_countup(d->list[i].value);
} else {
- if (convert_string_keys && ((pdf_obj *)ctx->stack_top[-2])->type == PDF_STRING) {
+ if (convert_string_keys && (pdfi_type_of((pdf_obj *)ctx->stack_top[-2]) == PDF_STRING)) {
pdf_name *n;
code = pdfi_dict_name_from_string(ctx, (pdf_string *)ctx->stack_top[-2], &n);
if (code < 0) {
@@ -266,7 +266,7 @@ static int pdfi_dict_find_unsorted(pdf_context *ctx, pdf_dict *d, const char *Ke
for (i=0;i< d->entries;i++) {
t = (pdf_name *)d->list[i].key;
- if (t && t->type == PDF_NAME) {
+ if (t && pdfi_type_of(t) == PDF_NAME) {
if (pdfi_name_is((pdf_name *)t, Key)) {
return i;
}
@@ -315,14 +315,14 @@ int pdfi_dict_get_common(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj
*o = NULL;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
index = pdfi_dict_find(ctx, d, Key, true);
if (index < 0)
return index;
- if (d->list[index].value->type == PDF_INDIRECT) {
+ if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) {
pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value;
if (r->ref_object_num == d->object_num)
@@ -340,8 +340,11 @@ int pdfi_dict_get_common(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj
* 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)
- {
+ if ((*o) < (pdf_obj *)(uintptr_t)(TOKEN__LAST_KEY)) {
+ /* "FAST" object, therefore can't be a problem. */
+ pdfi_countdown(d->list[index].value);
+ d->list[index].value = *o;
+ } else if ((*o)->object_num == 0 || (*o)->object_num != d->object_num) {
pdfi_countdown(d->list[index].value);
d->list[index].value = *o;
} else {
@@ -364,7 +367,7 @@ int pdfi_dict_get_no_deref(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, p
*o = NULL;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
index = pdfi_dict_find_key(ctx, d, Key, true);
@@ -386,14 +389,14 @@ int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf
*o = NULL;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
index = pdfi_dict_find_key(ctx, d, Key, true);
if (index < 0)
return index;
- if (d->list[index].value->type == PDF_INDIRECT) {
+ if (pdfi_type_of(d->list[index].value) == 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);
@@ -414,14 +417,14 @@ int pdfi_dict_get_ref(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_indire
*o = NULL;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
index = pdfi_dict_find(ctx, d, Key, true);
if (index < 0)
return index;
- if (d->list[index].value->type == PDF_INDIRECT) {
+ if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) {
*o = (pdf_indirect_ref *)d->list[index].value;
pdfi_countup(*o);
return 0;
@@ -444,7 +447,7 @@ static int pdfi_dict_get_no_store_R_inner(pdf_context *ctx, pdf_dict *d, const c
*o = NULL;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
if (strKey == NULL)
@@ -455,7 +458,7 @@ static int pdfi_dict_get_no_store_R_inner(pdf_context *ctx, pdf_dict *d, const c
if (index < 0)
return index;
- if (d->list[index].value->type == PDF_INDIRECT) {
+ if (pdfi_type_of(d->list[index].value) == 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);
@@ -500,7 +503,7 @@ int pdfi_dict_get_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_t
if (code < 0)
return code;
- if ((*o)->type != type) {
+ if (pdfi_type_of(*o) != type) {
pdfi_countdown(*o);
*o = NULL;
return_error(gs_error_typecheck);
@@ -524,15 +527,14 @@ pdfi_dict_get_int2(pdf_context *ctx, pdf_dict *d, const char *Key1,
int pdfi_dict_get_int(pdf_context *ctx, pdf_dict *d, const char *Key, int64_t *i)
{
int code;
- pdf_num *n;
+ pdf_obj *n;
- code = pdfi_dict_get_type(ctx, d, Key, PDF_INT, (pdf_obj **)&n);
+ code = pdfi_dict_get(ctx, d, Key, &n);
if (code < 0)
return code;
-
- *i = n->value.i;
+ code = pdfi_obj_to_int(ctx, n, i);
pdfi_countdown(n);
- return 0;
+ return code;
}
/* Get an int from dict, and if undefined, return provided default */
@@ -566,15 +568,24 @@ pdfi_dict_get_bool2(pdf_context *ctx, pdf_dict *d, const char *Key1,
int pdfi_dict_get_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool *val)
{
int code;
- pdf_bool *b;
+ pdf_obj *b;
- code = pdfi_dict_get_type(ctx, d, Key, PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get(ctx, d, Key, &b);
if (code < 0)
return code;
- *val = b->value;
+ if (b == PDF_TRUE_OBJ) {
+ *val = 1;
+ return 0;
+ } else if (b == PDF_FALSE_OBJ) {
+ *val = 0;
+ return 0;
+ }
+
pdfi_countdown(b);
- return 0;
+
+ *val = 0; /* Be consistent at least! */
+ return_error(gs_error_typecheck);
}
int pdfi_dict_get_number2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, double *f)
@@ -590,23 +601,15 @@ int pdfi_dict_get_number2(pdf_context *ctx, pdf_dict *d, const char *Key1, const
int pdfi_dict_get_number(pdf_context *ctx, pdf_dict *d, const char *Key, double *f)
{
int code;
- pdf_num *o;
+ pdf_obj *o;
- code = pdfi_dict_get(ctx, d, Key, (pdf_obj **)&o);
+ code = pdfi_dict_get(ctx, d, Key, &o);
if (code < 0)
return code;
- if (o->type == PDF_INT) {
- *f = (double)(o->value.i);
- } else {
- if (o->type == PDF_REAL){
- *f = o->value.d;
- } else {
- pdfi_countdown(o);
- return_error(gs_error_typecheck);
- }
- }
+ code = pdfi_obj_to_real(ctx, o, f);
pdfi_countdown(o);
- return 0;
+
+ return code;
}
/* convenience functions for retrieving arrys, see shadings and functions */
@@ -627,7 +630,7 @@ int fill_domain_from_dict(pdf_context *ctx, float *parray, int size, pdf_dict *d
code = pdfi_dict_get(ctx, dict, "Domain", (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_countdown(a);
return_error(gs_error_typecheck);
}
@@ -659,7 +662,7 @@ int fill_float_array_from_dict(pdf_context *ctx, float *parray, int size, pdf_di
code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -685,13 +688,13 @@ int fill_bool_array_from_dict(pdf_context *ctx, bool *parray, int size, pdf_dict
{
int code, i;
pdf_array *a = NULL;
- pdf_bool *o;
+ pdf_obj *o;
uint64_t array_size;
code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_countdown(a);
return_error(gs_error_typecheck);
}
@@ -700,13 +703,20 @@ int fill_bool_array_from_dict(pdf_context *ctx, bool *parray, int size, pdf_dict
return_error(gs_error_rangecheck);
for (i=0;i< array_size;i++) {
- code = pdfi_array_get_type(ctx, a, (uint64_t)i, PDF_BOOL, (pdf_obj **)&o);
+ code = pdfi_array_get(ctx, a, (uint64_t)i, (pdf_obj **)&o);
if (code < 0) {
pdfi_countdown(a);
return_error(code);
}
- parray[i] = o->value;
- pdfi_countdown(o);
+ if (o == PDF_TRUE_OBJ) {
+ parray[i] = 1;
+ } else if (o == PDF_FALSE_OBJ) {
+ parray[i] = 0;
+ } else {
+ pdfi_countdown(o);
+ pdfi_countdown(a);
+ return_error(gs_error_typecheck);
+ }
}
pdfi_countdown(a);
return array_size;
@@ -722,7 +732,7 @@ int fill_matrix_from_dict(pdf_context *ctx, float *parray, pdf_dict *dict)
code = pdfi_dict_get(ctx, dict, "Matrix", (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_countdown(a);
return_error(gs_error_typecheck);
}
@@ -758,7 +768,7 @@ int pdfi_make_float_array_from_dict(pdf_context *ctx, float **parray, pdf_dict *
code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_countdown(a);
return_error(gs_error_typecheck);
}
@@ -795,7 +805,7 @@ int pdfi_make_int_array_from_dict(pdf_context *ctx, int **parray, pdf_dict *dict
code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a);
if (code < 0)
return code;
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_countdown(a);
return_error(gs_error_typecheck);
}
@@ -828,10 +838,10 @@ int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *valu
int i;
pdf_dict_entry *new_list;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
- if (Key->type != PDF_NAME)
+ if (pdfi_type_of(Key) != PDF_NAME)
return_error(gs_error_typecheck);
/* First, do we have a Key/value pair already ? */
@@ -883,6 +893,60 @@ int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *valu
return 0;
}
+/*
+ * Be very cautious using this routine; it does not check to see if a key already exists
+ * in a dictionary!. This is initially at least intended for use by the font code, to build
+ * a CharStrings dictionary. We do that by adding each glyph individually with a name
+ * created from a loop counter, so we know there cannot be any duplicates, and the time
+ * taken to check that each of 64K names was unique was quite significant.
+ * See bug #705534, the old PDF interpreter (nullpage, 72 dpi) runs this file in ~20 seconds
+ * pdfi runs it in around 40 seconds. With this change it runs in around 3 seconds. THis is,
+ * of course, an extreme example.
+ */
+int pdfi_dict_put_unchecked(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value)
+{
+ int i, code = 0;
+ pdf_dict_entry *new_list;
+ pdf_obj *key = NULL;
+
+ code = pdfi_name_alloc(ctx, (byte *)Key, strlen(Key), &key);
+ if (code < 0)
+ return code;
+ pdfi_countup(key);
+
+ /* 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->list[i].key == NULL) {
+ d->list[i].key = key;
+ d->list[i].value = value;
+ pdfi_countup(value);
+ d->entries++;
+ return 0;
+ }
+ }
+ }
+
+ 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_list, d->list, d->size * sizeof(pdf_dict_entry));
+
+ gs_free_object(ctx->memory, d->list, "pdfi_dict_put key/value reallocation");
+
+ d->list = new_list;
+
+ d->list[d->size].key = key;
+ d->list[d->size].value = value;
+ d->size++;
+ d->entries++;
+ pdfi_countup(value);
+
+ return 0;
+}
+
/* Put into dictionary with key as string */
int pdfi_dict_put(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value)
{
@@ -914,15 +978,9 @@ int pdfi_dict_put_int(pdf_context *ctx, pdf_dict *d, const char *key, int64_t va
int pdfi_dict_put_bool(pdf_context *ctx, pdf_dict *d, const char *key, bool value)
{
- int code;
- pdf_bool *obj = NULL;
-
- code = pdfi_object_alloc(ctx, PDF_BOOL, 0, (pdf_obj **)&obj);
- if (code < 0)
- return code;
+ pdf_obj *obj = (value ? PDF_TRUE_OBJ : PDF_FALSE_OBJ);
- obj->value = value;
- return pdfi_dict_put(ctx, d, key, (pdf_obj *)obj);
+ return pdfi_dict_put(ctx, d, key, obj);
}
int pdfi_dict_put_name(pdf_context *ctx, pdf_dict *d, const char *key, const char *name)
@@ -957,7 +1015,7 @@ int pdfi_dict_known(pdf_context *ctx, pdf_dict *d, const char *Key, bool *known)
{
int i;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
*known = false;
@@ -972,7 +1030,7 @@ int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *k
{
int i;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
*known = false;
@@ -1030,6 +1088,25 @@ int pdfi_dict_knownget_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_
return 1;
}
+int pdfi_dict_knownget_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool *b)
+{
+ bool known = false;
+ int code;
+
+ code = pdfi_dict_known(ctx, d, Key, &known);
+ if (code < 0)
+ return code;
+
+ if (known == false)
+ return 0;
+
+ code = pdfi_dict_get_bool(ctx, d, Key, b);
+ if (code < 0)
+ return code;
+
+ return 1;
+}
+
/* Like pdfi_dict_knownget_type() but retrieves numbers (two possible types)
*/
int pdfi_dict_knownget_number(pdf_context *ctx, pdf_dict *d, const char *Key, double *f)
@@ -1055,7 +1132,7 @@ int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value
{
int code;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
while (1) {
@@ -1078,7 +1155,7 @@ int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value
continue;
}
- if (d->list[*index].value->type == PDF_INDIRECT) {
+ if (pdfi_type_of(d->list[*index].value) == PDF_INDIRECT) {
pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[*index].value;
pdf_obj *o;
@@ -1113,7 +1190,7 @@ int pdfi_dict_key_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, uint64_t *i
{
uint64_t *i = index;
- if (d->type != PDF_DICT)
+ if (pdfi_type_of(d) != PDF_DICT)
return_error(gs_error_typecheck);
while (1) {
@@ -1169,7 +1246,7 @@ int64_t pdfi_stream_length(pdf_context *ctx, pdf_stream *stream)
int64_t Length = 0;
int code;
- if (stream->type != PDF_STREAM)
+ if (pdfi_type_of(stream) != PDF_STREAM)
return 0;
if (stream->length_valid)
@@ -1195,14 +1272,14 @@ int64_t pdfi_stream_length(pdf_context *ctx, pdf_stream *stream)
*/
gs_offset_t pdfi_stream_offset(pdf_context *ctx, pdf_stream *stream)
{
- if (stream->type != PDF_STREAM)
+ if (pdfi_type_of(stream) != PDF_STREAM)
return 0;
return stream->stream_offset;
}
pdf_stream *pdfi_stream_parent(pdf_context *ctx, pdf_stream *stream)
{
- if (stream->type != PDF_STREAM)
+ if (pdfi_type_of(stream) != PDF_STREAM)
return 0;
return (pdf_stream *)stream->parent_obj;
}
@@ -1233,11 +1310,15 @@ void pdfi_clear_stream_parent(pdf_context *ctx, pdf_stream *stream)
int pdfi_dict_from_obj(pdf_context *ctx, pdf_obj *obj, pdf_dict **dict)
{
*dict = NULL;
- if (obj->type == PDF_DICT)
- *dict = (pdf_dict *)obj;
- else if (obj->type == PDF_STREAM)
- *dict = ((pdf_stream *)obj)->stream_dict;
- else
- return_error(gs_error_typecheck);
+ switch (pdfi_type_of(obj)) {
+ case PDF_DICT:
+ *dict = (pdf_dict *)obj;
+ break;
+ case PDF_STREAM:
+ *dict = ((pdf_stream *)obj)->stream_dict;
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
return 0;
}
diff --git a/pdf/pdf_dict.h b/pdf/pdf_dict.h
index c5a8743b..90cac6af 100644
--- a/pdf/pdf_dict.h
+++ b/pdf/pdf_dict.h
@@ -28,7 +28,7 @@ static inline int pdfi_dict_get(pdf_context *ctx, pdf_dict *d, const char *Key,
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);
+ return pdfi_dict_get_common(ctx, d, Key, o, false);
}
@@ -42,8 +42,10 @@ int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *k
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_dict_knownget_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool *b);
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, bool replace);
+int pdfi_dict_put_unchecked(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value);
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);
diff --git a/pdf/pdf_doc.c b/pdf/pdf_doc.c
index be71dfcb..7febe60a 100644
--- a/pdf/pdf_doc.c
+++ b/pdf/pdf_doc.c
@@ -55,13 +55,13 @@ int pdfi_read_Root(pdf_context *ctx)
}
pdfi_countdown(d);
- if (o1->type == PDF_INDIRECT) {
+ if (pdfi_type_of(o1) == PDF_INDIRECT) {
code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o1)->ref_object_num, ((pdf_indirect_ref *)o1)->ref_generation_num, &o);
pdfi_countdown(o1);
if (code < 0)
return code;
- if (o->type != PDF_DICT) {
+ if (pdfi_type_of(o) != PDF_DICT) {
pdfi_countdown(o);
return_error(gs_error_typecheck);
}
@@ -73,23 +73,40 @@ int pdfi_read_Root(pdf_context *ctx)
}
o1 = o;
} else {
- if (o1->type != PDF_DICT) {
+ if (pdfi_type_of(o1) != PDF_DICT) {
pdfi_countdown(o1);
- return_error(gs_error_typecheck);
+ if (ctx->Root == NULL)
+ return_error(gs_error_typecheck);
+ return 0;
}
}
code = pdfi_dict_get_type(ctx, (pdf_dict *)o1, "Type", PDF_NAME, &o);
if (code < 0) {
- pdfi_countdown(o1);
- return code;
+ bool known = false;
+
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGTYPE, "pdfi_read_Root", NULL);
+
+ /* Missing the *required* /Type key! See if it has /Pages at least, if it does carry on */
+ code = pdfi_dict_known(ctx, (pdf_dict *)o1, "Pages", &known);
+ if (code < 0 || known == false) {
+ pdfi_countdown(o1);
+ return code;
+ }
}
- if (pdfi_name_strcmp((pdf_name *)o, "Catalog") != 0){
+ else {
+ if (pdfi_name_strcmp((pdf_name *)o, "Catalog") != 0){
+ pdfi_countdown(o);
+ pdfi_countdown(o1);
+ /* If we repaired the file, we may already have spotted a potential Root dictionary
+ * so if the one we found here isn't valid, try the one we found when scanning
+ */
+ if (ctx->Root == NULL)
+ return_error(gs_error_syntaxerror);
+ return 0;
+ }
pdfi_countdown(o);
- pdfi_countdown(o1);
- return_error(gs_error_syntaxerror);
}
- pdfi_countdown(o);
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "\n");
@@ -101,6 +118,183 @@ int pdfi_read_Root(pdf_context *ctx)
return 0;
}
+static int Info_check_dict(pdf_context *ctx, pdf_dict *d);
+
+static int Info_check_array(pdf_context *ctx, pdf_array *a)
+{
+ int code = 0, i = 0;
+ pdf_obj *array_obj = NULL;
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_fetch_recursing(ctx, a, i, &array_obj, true, true);
+ if (code < 0)
+ goto error;
+
+ switch(pdfi_type_of(array_obj)) {
+ case PDF_DICT:
+ if (array_obj->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, array_obj->object_num);
+ if (code < 0)
+ goto error;
+ }
+ code = Info_check_dict(ctx, (pdf_dict *)array_obj);
+ if (code < 0)
+ goto error;
+ break;
+ case PDF_ARRAY:
+ if (array_obj->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, array_obj->object_num);
+ if (code < 0)
+ goto error;
+ }
+ code = Info_check_array(ctx, (pdf_array *)array_obj);
+ if (code < 0)
+ goto error;
+ break;
+ default:
+ break;
+ }
+
+ pdfi_countdown(array_obj);
+ array_obj = NULL;
+ }
+error:
+ pdfi_countdown(array_obj);
+ pdfi_loop_detector_cleartomark(ctx);
+ return code;
+}
+
+static int Info_check_dict(pdf_context *ctx, pdf_dict *d)
+{
+ int code = 0;
+ uint64_t index = 0;
+ pdf_name *Key = NULL;
+ pdf_obj *Value = NULL;
+
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, d, (pdf_obj **)&Key, &Value, &index);
+ if (code < 0) {
+ if (code == gs_error_undefined)
+ code = 0;
+ goto error;
+ }
+
+ while (code >= 0) {
+ switch(pdfi_type_of(Value)) {
+ case PDF_DICT:
+ if (Value->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, Value->object_num);
+ if (code < 0)
+ goto error;
+ }
+ code = Info_check_dict(ctx, (pdf_dict *)Value);
+ if (code < 0)
+ goto error;
+ break;
+ case PDF_ARRAY:
+ if (Value->object_num != 0) {
+ code = pdfi_loop_detector_add_object(ctx, Value->object_num);
+ if (code < 0)
+ goto error;
+ }
+ code = Info_check_array(ctx, (pdf_array *)Value);
+ if (code < 0)
+ goto error;
+ break;
+ default:
+ break;
+ }
+ pdfi_countdown(Key);
+ Key = NULL;
+ pdfi_countdown(Value);
+ Value = NULL;
+
+ code = pdfi_dict_next(ctx, d, (pdf_obj **)&Key, &Value, &index);
+ if (code == gs_error_undefined) {
+ code = 0;
+ break;
+ }
+ }
+error:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+ pdfi_loop_detector_cleartomark(ctx);
+ return code;
+}
+
+static int pdfi_sanitize_Info_references(pdf_context *ctx, pdf_dict *Info)
+{
+ int code = 0;
+ uint64_t index = 0;
+ pdf_name *Key = NULL;
+ pdf_obj *Value = NULL;
+
+restart_scan:
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
+ code = pdfi_dict_first(ctx, Info, (pdf_obj **)&Key, &Value, &index);
+ if (code == gs_error_undefined) {
+ code = 0;
+ goto error;
+ }
+
+ while (code >= 0) {
+ switch(pdfi_type_of(Value)) {
+ case PDF_DICT:
+ code = Info_check_dict(ctx, (pdf_dict *)Value);
+ break;
+ case PDF_ARRAY:
+ code = Info_check_array(ctx, (pdf_array *)Value);
+ break;
+ default:
+ code = 0;
+ break;
+ }
+ pdfi_countdown(Value);
+ Value = NULL;
+ if (code < 0) {
+ code = pdfi_dict_delete_pair(ctx, Info, Key);
+ if (code < 0)
+ goto error;
+ pdfi_countdown(Key);
+ Key = NULL;
+
+ pdfi_loop_detector_cleartomark(ctx);
+ goto restart_scan;
+ }
+ pdfi_countdown(Key);
+ Key = NULL;
+
+ pdfi_loop_detector_cleartomark(ctx);
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0) {
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+ return code;
+ }
+
+ code = pdfi_dict_next(ctx, Info, (pdf_obj **)&Key, &Value, &index);
+ if (code == gs_error_undefined) {
+ code = 0;
+ break;
+ }
+ }
+error:
+ pdfi_countdown(Key);
+ pdfi_countdown(Value);
+ pdfi_loop_detector_cleartomark(ctx);
+ return code;
+}
+
int pdfi_read_Info(pdf_context *ctx)
{
pdf_dict *Info;
@@ -121,6 +315,20 @@ int pdfi_read_Info(pdf_context *ctx)
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "\n");
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ goto error;
+ code = pdfi_loop_detector_add_object(ctx, Info->object_num);
+ if (code < 0)
+ goto error1;
+
+ /* sanitize Info for circular references */
+ code = pdfi_sanitize_Info_references(ctx, Info);
+ if (code < 0)
+ goto error1;
+
+ (void)pdfi_loop_detector_cleartomark(ctx);
+
pdfi_device_set_flags(ctx);
pdfi_pdfmark_write_docinfo(ctx, Info);
@@ -129,12 +337,19 @@ int pdfi_read_Info(pdf_context *ctx)
*/
ctx->Info = Info;
return 0;
+
+error1:
+ pdfi_loop_detector_cleartomark(ctx);
+error:
+ pdfi_countdown(Info);
+ return code;
}
int pdfi_read_Pages(pdf_context *ctx)
{
pdf_obj *o, *o1;
- int code;
+ pdf_array *a = NULL;
+ int code, pagecount = 0;
double d;
if (ctx->args.pdfdebug)
@@ -144,15 +359,15 @@ int pdfi_read_Pages(pdf_context *ctx)
if (code < 0)
return code;
- if (o1->type == PDF_INDIRECT) {
+ if (pdfi_type_of(o1) == PDF_INDIRECT) {
code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o1)->ref_object_num, ((pdf_indirect_ref *)o1)->ref_generation_num, &o);
pdfi_countdown(o1);
if (code < 0)
return code;
- if (o->type != PDF_DICT) {
+ if (pdfi_type_of(o) != PDF_DICT) {
pdfi_countdown(o);
- if (o->type == PDF_INDIRECT)
+ if (pdfi_type_of(o) == PDF_INDIRECT)
pdfi_set_error(ctx, 0, NULL, E_PDF_BADPAGEDICT, "pdfi_read_Pages", (char *)"*** Error: Something is wrong with the Pages dictionary. Giving up.");
else
pdfi_set_error(ctx, 0, NULL, E_PDF_BADPAGEDICT, "pdfi_read_Pages", (char *)"*** Error: Something is wrong with the Pages dictionary. Giving up.\n Double indirect reference. Loop in Pages tree?");
@@ -166,7 +381,7 @@ int pdfi_read_Pages(pdf_context *ctx)
}
o1 = o;
} else {
- if (o1->type != PDF_DICT) {
+ if (pdfi_type_of(o1) != PDF_DICT) {
pdfi_countdown(o1);
return_error(gs_error_typecheck);
}
@@ -212,6 +427,86 @@ int pdfi_read_Pages(pdf_context *ctx)
ctx->num_pages = (int)floor(d);
}
+ /* A simple confidence check in the value of Count. We only do this because
+ * the OSS-fuzz tool keeps on coming up with files that time out because the
+ * initial Count is insanely huge, and we spend much time trying to find
+ * millions of pages which don't exist.
+ */
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)o1, "Kids", PDF_ARRAY, (pdf_obj **)&a);
+ if (code == 0)
+ code = gs_note_error(gs_error_undefined);
+ if (code < 0) {
+ pdfi_countdown(o1);
+ return code;
+ }
+
+ /* Firstly check if the Kids array has enough nodes, in which case it's
+ * probably flat (the common case)
+ */
+ if (a->size != ctx->num_pages) {
+ int i = 0;
+ pdf_obj *p = NULL, *p1 = NULL;
+ pdf_num *c = NULL;
+
+ /* Either its not a flat tree, or the top node /Count is incorrect.
+ * Get each entry in the Kids array in turn and total the /Count of
+ * each node and add any leaf nodes.
+ */
+ for (i=0;i < a->size; i++) {
+ code = pdfi_array_get(ctx, a, i, &p);
+ if (code < 0)
+ continue;
+ if (pdfi_type_of(p) != PDF_DICT) {
+ pdfi_countdown(p);
+ p = NULL;
+ continue;
+ }
+ code = pdfi_dict_knownget_type(ctx, (pdf_dict *)p, "Type", PDF_NAME, (pdf_obj **)&p1);
+ if (code <= 0) {
+ pdfi_countdown(p);
+ p = NULL;
+ continue;
+ }
+ if (pdfi_name_is((pdf_name *)p1, "Page")) {
+ pagecount++;
+ } else {
+ if (pdfi_name_is((pdf_name *)p1, "Pages")) {
+ code = pdfi_dict_knownget(ctx, (pdf_dict *)p, "Count", (pdf_obj **)&c);
+ if (code >= 0) {
+ if (pdfi_type_of(c) == PDF_INT)
+ pagecount += c->value.i;
+ if (pdfi_type_of(c) == PDF_REAL)
+ pagecount += (int)c->value.d;
+ pdfi_countdown(c);
+ c = NULL;
+ }
+ }
+ }
+ pdfi_countdown(p1);
+ p1 = NULL;
+ pdfi_countdown(p);
+ p = NULL;
+ }
+ } else
+ pagecount = a->size;
+
+ pdfi_countdown(a);
+
+ /* If the count of the top level of the tree doesn't match the /Count
+ * of the root node then something is wrong. We could abort right now
+ * and will if this continues to be a problem, but initially let's assume
+ * the count of the top level is correct and the root node /Count is wrong.
+ * This will allow us to recover if only the root /Count gets corrupted.
+ * In future we could also try validating the entire tree at this point,
+ * though I suspect that's pointless; if the tree is corrupted we aren't
+ * likely to get much that's usable from it.
+ */
+ if (pagecount != ctx->num_pages) {
+ ctx->num_pages = pagecount;
+ code = pdfi_dict_put_int(ctx, (pdf_dict *)o1, "Count", ctx->num_pages);
+ pdfi_set_error(ctx, 0, NULL, E_PDF_BADPAGECOUNT, "pdfi_read_Pages", NULL);
+ }
+
/* We don't pdfi_countdown(o1) now, because we've transferred our
* reference to the pointer in the pdf_context structure.
*/
@@ -278,12 +573,12 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
if (code < 0)
goto errorExit;
- if (node->type != PDF_INDIRECT && node->type != PDF_DICT) {
+ if (pdfi_type_of(node) != PDF_INDIRECT && pdfi_type_of(node) != PDF_DICT) {
code = gs_note_error(gs_error_typecheck);
goto errorExit;
}
- if (node->type == PDF_INDIRECT) {
+ if (pdfi_type_of(node) == PDF_INDIRECT) {
code = pdfi_dereference(ctx, node->ref_object_num, node->ref_generation_num,
(pdf_obj **)&child);
if (code < 0) {
@@ -295,7 +590,7 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
if (code < 0)
goto errorExit;
}
- if (child->type != PDF_DICT) {
+ if (pdfi_type_of(child) != PDF_DICT) {
code = gs_note_error(gs_error_typecheck);
goto errorExit;
}
@@ -352,6 +647,11 @@ static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **p
code = gs_note_error(gs_error_circular_reference);
goto errorExit;
}
+ if (node->object_num > 0) {
+ code = pdfi_loop_detector_add_object(ctx, node->object_num);
+ if (code < 0)
+ goto errorExit;
+ }
}
child = (pdf_dict *)node;
pdfi_countup(child);
@@ -423,6 +723,10 @@ int pdfi_get_page_dict(pdf_context *ctx, pdf_dict *d, uint64_t page_num, uint64_
return code;
pdfi_countup(inheritable);
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0)
+ return code;
+
/* if we are being passed any inherited values from our parent, copy them now */
if (inherited != NULL) {
code = pdfi_dict_copy(ctx, inheritable, inherited);
@@ -543,6 +847,7 @@ int pdfi_get_page_dict(pdf_context *ctx, pdf_dict *d, uint64_t page_num, uint64_
code = 1;
exit:
+ pdfi_loop_detector_cleartomark(ctx);
pdfi_countdown(inheritable);
pdfi_countdown(Kids);
pdfi_countdown(child);
@@ -599,12 +904,15 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
{
pdf_dict *typedict = NULL;
pdf_dict *Parent = NULL;
+ pdf_name *n = NULL;
int code;
*o = NULL;
/* Check the provided dict, stream_dict can be NULL if we are trying to find a Default* ColorSpace */
if (dict != NULL) {
+ bool deref_parent = true;
+
code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict);
if (code < 0)
goto exit;
@@ -615,30 +923,40 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
}
/* 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;
+ /* If the current dictionary is a Page dictionary, do NOT dereference it's Parent, as that
+ * will be the Pages tree, and we will end up with circular references, causing a memory leak.
+ */
+ if (pdfi_dict_knownget_type(ctx, dict, "Type", PDF_NAME, (pdf_obj **)&n) > 0) {
+ if (pdfi_name_is(n, "Page"))
+ deref_parent = false;
+ pdfi_countdown(n);
+ }
- code = pdfi_loop_detector_add_object(ctx, dict->object_num);
- if (code < 0) {
+ if (deref_parent) {
+ code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent);
+ if (code < 0)
+ goto exit;
+ if (code > 0) {
+ if (ctx->page.CurrentPageDict != NULL && 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);
- return code;
+ if (code != gs_error_undefined)
+ goto exit;
}
- 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;
}
@@ -788,6 +1106,9 @@ static int pdfi_doc_mark_outline(pdf_context *ctx, pdf_dict *outline)
pdf_dict *child = NULL;
pdf_dict *Next = NULL;
+ if (outline == (pdf_dict *)PDF_NULL_OBJ)
+ return 0;
+
/* Mark the outline */
/* NOTE: I think the pdfmark for this needs to be written before the children
* because I think pdfwrite relies on the order of things.
@@ -803,7 +1124,7 @@ static int pdfi_doc_mark_outline(pdf_context *ctx, pdf_dict *outline)
/* Handle any 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) {
+ if (code < 0 || pdfi_type_of(child) != PDF_DICT) {
/* TODO: flag a warning? */
code = 0;
goto exit;
@@ -829,7 +1150,7 @@ static int pdfi_doc_mark_outline(pdf_context *ctx, pdf_dict *outline)
code = 0;
goto exit;
}
- if (code < 0 || Next->type != PDF_DICT)
+ if (code < 0 || pdfi_type_of(Next) != PDF_DICT)
goto exit;
pdfi_countdown(child);
@@ -869,12 +1190,15 @@ static int pdfi_doc_Outlines(pdf_context *ctx)
/* Handle any children (don't deref them, we don't want to leave them hanging around) */
code = pdfi_dict_get_no_store_R(ctx, Outlines, "First", (pdf_obj **)&outline);
- if (code < 0 || outline->type != PDF_DICT) {
+ if (code < 0 || pdfi_type_of(outline) != PDF_DICT) {
/* TODO: flag a warning? */
code = 0;
goto exit;
}
+ if (pdfi_type_of(outline) != PDF_DICT)
+ goto exit; /* Exit with no error? */
+
if (outline->object_num != 0) {
code = pdfi_loop_detector_add_object(ctx, outline->object_num);
if (code < 0)
@@ -900,7 +1224,7 @@ static int pdfi_doc_Outlines(pdf_context *ctx)
code = 0;
goto exit;
}
- if (code < 0 || outline->type != PDF_DICT)
+ if (code < 0 || pdfi_type_of(Next) != PDF_DICT)
goto exit;
pdfi_countdown(outline);
diff --git a/pdf/pdf_errors.h b/pdf/pdf_errors.h
index e52a6c74..d62d6acb 100644
--- a/pdf/pdf_errors.h
+++ b/pdf/pdf_errors.h
@@ -24,6 +24,7 @@ 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_PREV_NOT_XREF_STREAM, "The /Prev entry in an XrefStm dictionary did not point to an XrefStm"),
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"),
@@ -52,5 +53,11 @@ 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)."),
-
+PARAM(E_PDF_GROUP_NO_CS, "Group attributes dictionary is missing /CS"),
+PARAM(E_BAD_GROUP_DICT, "Error retrieving Group dictionary for a page or XObject"),
+PARAM(E_BAD_HALFTONE, "Error setting a halftone"),
+PARAM(E_PDF_BADENCRYPT, "Encrypt diciotnary not a dictionary"),
+PARAM(E_PDF_MISSINGTYPE, "A dictionary is missing a required /Type key."),
+PARAM(E_PDF_NESTEDTOODEEP, "Dictionaries/arrays nested too deeply"),
+PARAM(E_PDF_BADPAGECOUNT, "page tree root node /Count did not match the actual number of pages in the tree."),
#undef PARAM
diff --git a/pdf/pdf_fapi.c b/pdf/pdf_fapi.c
index 3e4420c4..7fb7c954 100644
--- a/pdf/pdf_fapi.c
+++ b/pdf/pdf_fapi.c
@@ -35,12 +35,14 @@
#include "pdf_dict.h"
#include "pdf_array.h"
#include "pdf_font.h"
-#include "pdf_font.h"
#include "gscencs.h"
#include "gsagl.h"
#include "gxfont1.h" /* for gs_font_type1_s */
#include "gscrypt1.h" /* for crypt_c1 */
+extern single_glyph_list_t SingleGlyphList[];
+
+
/* forward declarations for the pdfi_ff_stub definition */
static int
pdfi_fapi_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, unsigned short *ret);
@@ -70,6 +72,9 @@ static int
pdfi_fapi_serialize_tt_font(gs_fapi_font * ff, void *buf, int buf_size);
static int
+pdfi_fapi_retrieve_tt_font(gs_fapi_font * ff, void **buf, int *buf_size);
+
+static int
pdfi_fapi_get_charstring(gs_fapi_font *ff, int index, byte *buf, ushort buf_length);
static int
@@ -130,6 +135,7 @@ static const gs_fapi_font pdfi_ff_stub = {
pdfi_fapi_get_raw_subr, /* get_raw_subr */
pdfi_fapi_get_glyph, /* get_glyph */
pdfi_fapi_serialize_tt_font, /* serialize_tt_font */
+ pdfi_fapi_retrieve_tt_font, /* retrieve_tt_font */
pdfi_fapi_get_charstring, /* get_charstring */
pdfi_fapi_get_charstring_name, /* get_charstring_name */
pdfi_get_glyphdirectory_data, /* get_GlyphDirectory_data_ptr */
@@ -248,7 +254,7 @@ pdfi_fapi_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, uns
{
if (pfont->FontType == ft_encrypted2) {
pdf_font_cff *pdffont2 = (pdf_font_cff *)pfont->client_data;
- *ret = pdffont2->NumGlobalSubrs;
+ *ret = pdffont2->GlobalSubrs == NULL ? 0 : pdfi_array_size(pdffont2->GlobalSubrs);
}
else {
*ret = 0;
@@ -260,11 +266,11 @@ pdfi_fapi_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, uns
{
if (pfont->FontType == ft_encrypted) {
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pfont->client_data;
- *ret = pdffont1->NumSubrs;
+ *ret = pdffont1->Subrs == NULL ? 0 : pdfi_array_size(pdffont1->Subrs);
}
else if (pfont->FontType == ft_encrypted2) {
pdf_font_cff *pdffont2 = (pdf_font_cff *)pfont->client_data;
- *ret = pdffont2->NumSubrs;
+ *ret = pdffont2->Subrs == NULL ? 0 : pdfi_array_size(pdffont2->Subrs);
}
else {
*ret = 0;
@@ -395,7 +401,7 @@ pdfi_fapi_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, uns
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pfont->client_data;
if (pdffont1->blendfontbbox != NULL) {
pdf_array *suba;
- pdf_num *v;
+ double d;
int ind, aind;
ind = index % 4;
aind = (index - ind) / 4;
@@ -404,17 +410,13 @@ pdfi_fapi_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, uns
*ret = 0;
break;
}
- code = pdfi_array_get(pdffont1->ctx, suba, ind, (pdf_obj **)&v);
+ code = pdfi_array_get_number(pdffont1->ctx, suba, ind, &d);
pdfi_countdown(suba);
if (code < 0) {
*ret = 0;
break;
}
- if (v->type == PDF_INT)
- *ret = (unsigned short)v->value.i;
- else
- *ret = (unsigned short)v->value.d;
- pdfi_countdown(v);
+ *ret = (unsigned short)d;
}
else {
*ret = 0;
@@ -447,8 +449,13 @@ pdfi_fapi_get_long(gs_fapi_font * ff, gs_fapi_font_feature var_id, int index, un
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pfont->client_data;
int i;
*ret = 0;
- for (i = 0; i < pdffont1->NumSubrs; i++) {
- *ret += pdffont1->Subrs[i].size;
+ for (i = 0; i < (pdffont1->Subrs == NULL ? 0 : pdfi_array_size(pdffont1->Subrs)); i++) {
+ pdf_string *subr_str = NULL;
+ code = pdfi_array_get_type(pdffont1->ctx, pdffont1->Subrs, i, PDF_STRING, (pdf_obj **)&subr_str);
+ if (code >= 0) {
+ *ret += subr_str->length;
+ }
+ pdfi_countdown(subr_str);
}
}
}
@@ -520,7 +527,7 @@ pdfi_fapi_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, fl
{
int array_index, subind;
pdf_array *suba;
- pdf_num *v;
+ double d;
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pbfont->client_data;
*ret = 0;
@@ -543,19 +550,13 @@ pdfi_fapi_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, fl
break;
}
- code = pdfi_array_get(pdffont1->ctx, suba, subind, (pdf_obj**)&v);
+ code = pdfi_array_get_number(pdffont1->ctx, suba, subind, &d);
pdfi_countdown(suba);
if (code < 0) {
code = 0;
break;
}
- if (v->type == PDF_INT) {
- *ret = (float)v->value.i;
- }
- else {
- *ret = (float)v->value.d;
- }
- pdfi_countdown(v);
+ *ret = (float)d;
}
break;
case gs_fapi_font_feature_BlendDesignMapArrayValue:
@@ -580,15 +581,11 @@ pdfi_fapi_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, fl
pdfi doesn't, hence the multiplications by 64.
*/
if ((i * 64) + (j * 64) + k == index) {
- pdf_num *n;
- code = pdfi_array_get(pdffont1->ctx, suba, i, (pdf_obj **)&n);
+ double d;
+ code = pdfi_array_get_number(pdffont1->ctx, suba, i, &d);
if (code < 0)
continue;
- if (n->type == PDF_INT)
- *ret = (float)n->value.i;
- else
- *ret = (float)n->value.d;
- pdfi_countdown(n);
+ *ret = (float)d;
pdfi_countdown(subsuba);
pdfi_countdown(suba);
goto gotit;
@@ -683,7 +680,7 @@ pdfi_fapi_get_gsubr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
int code = 0;
if (pfont->FontType == ft_encrypted2) {
pdf_font_cff *pdffont2 = (pdf_font_cff *)pfont->client_data;
- if (index > pdffont2->NumGlobalSubrs) {
+ if (index > (pdffont2->GlobalSubrs == NULL ? 0 : pdfi_array_size(pdffont2->GlobalSubrs))) {
code = gs_error_rangecheck;
}
else {
@@ -692,7 +689,7 @@ pdfi_fapi_get_gsubr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
code = pdfi_array_get(pdffont2->ctx, pdffont2->GlobalSubrs, index, (pdf_obj **)&subrstring);
if (code >= 0) {
- if (subrstring->type == PDF_STRING) {
+ if (pdfi_type_of(subrstring) == PDF_STRING) {
code = subrstring->length - leniv;
if (buf && buf_length >= code) {
if (ff->need_decrypt && pfont->data.lenIV >= 0) {
@@ -724,27 +721,35 @@ pdfi_fapi_get_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
if (pfont->FontType == ft_encrypted) {
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pfont->client_data;
- if (index > pdffont1->NumSubrs) {
+ if (index > (pdffont1->Subrs == NULL ? 0 : pdfi_array_size(pdffont1->Subrs))) {
code = gs_note_error(gs_error_rangecheck);
}
else {
int leniv = (pfont->data.lenIV > 0 ? pfont->data.lenIV : 0);
- if (pdffont1->Subrs[index].size > 0) {
- code = pdffont1->Subrs[index].size - leniv;
+ pdf_string *subr_str = NULL;
+
+ code = pdfi_array_get_type(pdffont1->ctx, pdffont1->Subrs, index, PDF_STRING, (pdf_obj **)&subr_str);
+ if (code >= 0) {
+ code = subr_str->length - leniv;
if (buf && buf_length >= code) {
if (ff->need_decrypt && pfont->data.lenIV >= 0) {
- decode_bytes(buf, pdffont1->Subrs[index].data, code + leniv, pfont->data.lenIV);
+ decode_bytes(buf, subr_str->data, code + leniv, pfont->data.lenIV);
}
else {
- memcpy(buf, pdffont1->Subrs[index].data, code);
+ memcpy(buf, subr_str->data, code);
}
}
}
+ else {
+ /* Ignore invalid or missing subrs */
+ code = 0;
+ }
+ pdfi_countdown(subr_str);
}
}
else if (pfont->FontType == ft_encrypted2) {
pdf_font_cff *pdffont2 = (pdf_font_cff *)pfont->client_data;
- if (index > pdffont2->NumSubrs) {
+ if (index > (pdffont2->Subrs == NULL ? 0 : pdfi_array_size(pdffont2->Subrs))) {
code = gs_error_rangecheck;
}
else {
@@ -756,7 +761,7 @@ pdfi_fapi_get_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
else
code = pdfi_array_get(pdffont2->ctx, pdffont2->Subrs, index, (pdf_obj **)&subrstring);
if (code >= 0) {
- if (subrstring->type == PDF_STRING) {
+ if (pdfi_type_of(subrstring) == PDF_STRING) {
if (subrstring->length > 0) {
code = subrstring->length - leniv;
if (buf && buf_length >= code) {
@@ -790,14 +795,23 @@ pdfi_fapi_get_raw_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
if (pfont->FontType == ft_encrypted) {
pdf_font_type1 *pdffont1 = (pdf_font_type1 *)pfont->client_data;
- if (index > pdffont1->NumSubrs) {
+ if (index > (pdffont1->Subrs == NULL ? 0 : pdfi_array_size(pdffont1->Subrs))) {
code = gs_error_rangecheck;
}
else {
- code = pdffont1->Subrs[index].size;
- if (buf && buf_length >= code) {
- memcpy(buf, pdffont1->Subrs[index].data, code);
+ pdf_string *subr_str = NULL;
+ code = pdfi_array_get_type(pdffont1->ctx, pdffont1->Subrs, index, PDF_STRING, (pdf_obj **)&subr_str);
+ if (code >= 0) {
+ code = subr_str->length;
+ if (buf && buf_length >= code) {
+ memcpy(buf, subr_str->data, code);
+ }
+ }
+ else {
+ /* Ignore missing or invalid subrs */
+ code = 0;
}
+ pdfi_countdown(subr_str);
}
}
return code;
@@ -815,8 +829,6 @@ pdfi_fapi_get_charstring_name(gs_fapi_font *ff, int index, byte *buf, ushort buf
return 0;
}
-extern single_glyph_list_t SingleGlyphList[];
-
static int
pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_string * charstring,
gs_string * name, gs_glyph ccode, gs_string * enc_char_name,
@@ -835,8 +847,8 @@ pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_
if (pttfont->substitute == false) {
gid = ccode;
- if (pttfont->cidtogidmap.size > (ccode << 1) + 1) {
- gid = pttfont->cidtogidmap.data[ccode << 1] << 8 | pttfont->cidtogidmap.data[(ccode << 1) + 1];
+ if (pttfont->cidtogidmap != NULL && pttfont->cidtogidmap->length > (ccode << 1) + 1) {
+ gid = pttfont->cidtogidmap->data[ccode << 1] << 8 | pttfont->cidtogidmap->data[(ccode << 1) + 1];
}
cr->client_char_code = ccode;
cr->char_codes[0] = gid;
@@ -933,8 +945,9 @@ pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_
code = (*ctx->get_glyph_name)((gs_font *)pbfont, ccode, &gname);
if (code >= 0) {
code = pdfi_name_alloc(ctx, (byte *) gname.data, gname.size, (pdf_obj **) &glyphname);
- if (code >= 0)
- pdfi_countup(glyphname);
+ if (code < 0)
+ return code;
+ pdfi_countup(glyphname);
}
if (code < 0) {
@@ -942,10 +955,12 @@ pdfi_fapi_get_glyphname_or_cid(gs_text_enum_t *penum, gs_font_base * pbfont, gs_
return code;
}
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 **)&charstr);
+ code = pdfi_map_glyph_name_via_agl(cfffont->CharStrings, glyphname, &charstr);
+ if (code < 0)
+ code = pdfi_dict_get(cfffont->ctx, cfffont->CharStrings, ".notdef", (pdf_obj **)&charstr);
}
+ pdfi_countdown(glyphname);
if (code < 0)
return code;
@@ -1121,7 +1136,6 @@ pdfi_fapi_get_glyph(gs_fapi_font * ff, gs_glyph char_code, byte * buf, int buf_l
pdf_name *encn;
int cstrlen = 0;
- /* This should only get called for Postscript-type fonts */
if (ff->is_type1) {
if (pbfont->FontType == ft_encrypted) {
@@ -1137,14 +1151,18 @@ pdfi_fapi_get_glyph(gs_fapi_font * ff, gs_glyph char_code, byte * buf, int buf_l
return code;
pdfi_countup(glyphname);
code = pdfi_dict_get_by_key(pdffont1->ctx, pdffont1->CharStrings, glyphname, (pdf_obj **)&charstring);
- pdfi_countdown(glyphname);
if (code < 0) {
- code = pdfi_dict_get(pdffont1->ctx, pdffont1->CharStrings, ".notdef", (pdf_obj **)&charstring);
+ code = pdfi_map_glyph_name_via_agl(pdffont1->CharStrings, glyphname, &charstring);
if (code < 0) {
- code = gs_note_error(gs_error_invalidfont);
- goto done;
+ code = pdfi_dict_get(pdffont1->ctx, pdffont1->CharStrings, ".notdef", (pdf_obj **)&charstring);
+ if (code < 0) {
+ pdfi_countdown(glyphname);
+ code = gs_note_error(gs_error_invalidfont);
+ goto done;
+ }
}
}
+ pdfi_countdown(glyphname);
cstrlen = charstring->length - leniv;
if (buf != NULL && cstrlen <= buf_length) {
if (ff->need_decrypt && pfont1->data.lenIV >= 0)
@@ -1261,7 +1279,16 @@ pdfi_fapi_get_glyph(gs_fapi_font * ff, gs_glyph char_code, byte * buf, int buf_l
}
}
else {
- code = gs_error_invalidaccess;
+ gs_font_type42 *pfont42 = (gs_font_type42 *)pbfont;
+ gs_glyph_data_t pgd;
+
+ code = pfont42->data.get_outline(pfont42, char_code, &pgd);
+ cstrlen = pgd.bits.size;
+ if (code >= 0) {
+ if (buf && buf_length >= cstrlen) {
+ memcpy(buf, pgd.bits.data, cstrlen);
+ }
+ }
}
done:
if (code < 0)
@@ -1277,6 +1304,19 @@ pdfi_fapi_serialize_tt_font(gs_fapi_font * ff, void *buf, int buf_size)
}
static int
+pdfi_fapi_retrieve_tt_font(gs_fapi_font * ff, void **buf, int *buf_size)
+{
+ gs_font_type42 *pfonttt = (gs_font_type42 *) ff->client_font_data;
+ pdf_font_truetype *pdfttf = (pdf_font_truetype *)pfonttt->client_data;
+
+ *buf = pdfttf->sfnt->data;
+ *buf_size = pdfttf->sfnt->length;
+
+ return 0;
+}
+
+
+static int
pdfi_get_glyphdirectory_data(gs_fapi_font * ff, int char_code,
const byte ** ptr)
{
@@ -1439,6 +1479,7 @@ pdfi_fapi_passfont(pdf_font *font, int subfont, char *fapi_request,
char *fapi_id = NULL;
int code = 0;
gs_string fdata;
+ gs_string *fdatap = &fdata;
gs_font_base *pbfont = (gs_font_base *)font->pfont;
gs_fapi_font local_pdf_ff_stub = pdfi_ff_stub;
gs_fapi_ttf_cmap_request symbolic_req[GS_FAPI_NUM_TTF_CMAP_REQ] = {{3, 0}, {1, 0}, {3, 1}, {3, 10}, {-1, -1}};
@@ -1450,16 +1491,15 @@ pdfi_fapi_passfont(pdf_font *font, int subfont, char *fapi_request,
}
if (font->pdfi_font_type == e_pdf_font_truetype) {
- fdata.data = ((pdf_font_truetype *)font)->sfnt.data;
- fdata.size = ((pdf_font_truetype *)font)->sfnt.size;
+ fdatap = NULL;
}
else if (font->pdfi_font_type == e_pdf_cidfont_type2) {
- fdata.data = ((pdf_cidfont_type2 *)font)->sfnt.data;
- fdata.size = ((pdf_cidfont_type2 *)font)->sfnt.size;
+ fdatap->data = ((pdf_cidfont_type2 *)font)->sfnt->data;
+ fdatap->size = ((pdf_cidfont_type2 *)font)->sfnt->length;
}
else {
- fdata.data = font_data;
- fdata.size = font_data_len;
+ fdatap->data = font_data;
+ fdatap->size = font_data_len;
}
if (font->pdfi_font_type == e_pdf_font_truetype) {
@@ -1476,7 +1516,7 @@ pdfi_fapi_passfont(pdf_font *font, int subfont, char *fapi_request,
(gs_font *)pbfont);
code =
- gs_fapi_passfont((gs_font *)pbfont, subfont, (char *)file_name, &fdata,
+ gs_fapi_passfont((gs_font *)pbfont, subfont, (char *)file_name, fdatap,
(char *)fapi_request, NULL, (char **)&fapi_id,
(gs_fapi_get_server_param_callback)
pdfi_get_server_param);
diff --git a/pdf/pdf_file.c b/pdf/pdf_file.c
index 5698866e..7f06a046 100644
--- a/pdf/pdf_file.c
+++ b/pdf/pdf_file.c
@@ -334,7 +334,7 @@ static int pdfi_Flate_filter(pdf_context *ctx, pdf_dict *d, stream *source, stre
(*new_stream)->strm = source;
source = *new_stream;
- if (d && d->type == PDF_DICT) {
+ if (d && pdfi_type_of(d) == PDF_DICT) {
Flate_source = (*new_stream)->strm;
code = pdfi_Predictor_filter(ctx, d, source, new_stream);
if (code < 0)
@@ -403,7 +403,7 @@ static int pdfi_LZW_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream
/* s_zlibD_template defined in base/szlibd.c */
s_LZW_set_defaults_inline(&lzs);
- if (d && d->type == PDF_DICT) {
+ if (d && pdfi_type_of(d) == PDF_DICT) {
code = pdfi_dict_get_int(ctx, d, "EarlyChange", &i);
if (code < 0 && code != gs_error_undefined)
return code;
@@ -421,7 +421,7 @@ static int pdfi_LZW_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream
(*new_stream)->strm = source;
source = *new_stream;
- if (d && d->type == PDF_DICT)
+ if (d && pdfi_type_of(d) == PDF_DICT)
pdfi_Predictor_filter(ctx, d, source, new_stream);
return 0;
}
@@ -473,21 +473,25 @@ pdfi_JPX_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode,
}
if (dict && pdfi_dict_get(ctx, dict, "ColorSpace", &csobj) == 0) {
/* parse the value */
- if (csobj->type == PDF_ARRAY) {
+ switch (pdfi_type_of(csobj)) {
+ case PDF_ARRAY:
/* assume it's the first array element */
code = pdfi_array_get(ctx, (pdf_array *)csobj, (uint64_t)0, (pdf_obj **)&csname);
if (code < 0) {
pdfi_countdown(csobj);
return code;
}
- } else if (csobj->type == PDF_NAME) {
+ break;
+ case PDF_NAME:
/* use the name directly */
csname = (pdf_name *)csobj;
csobj = NULL; /* To keep ref counting straight */
- } else {
+ break;
+ default:
dmprintf(ctx->memory, "warning: JPX ColorSpace value is an unhandled type!\n");
+ break;
}
- if (csname != NULL && csname->type == PDF_NAME) {
+ if (csname != NULL && pdfi_type_of(csname) == PDF_NAME) {
/* request raw index values if the colorspace is /Indexed */
if (pdfi_name_is(csname, "Indexed"))
state.colorspace = gs_jpx_cs_indexed;
@@ -613,7 +617,7 @@ static int pdfi_DCT_filter(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *de
return code;
}
- if (decode && decode->type == PDF_DICT) {
+ if (decode && pdfi_type_of(decode) == PDF_DICT) {
/* TODO: Why is this here? 'i' never gets used? */
code = pdfi_dict_get_int(ctx, decode, "ColorTransform", &i);
if (code < 0 && code != gs_error_undefined)
@@ -674,7 +678,7 @@ static int pdfi_CCITTFax_filter(pdf_context *ctx, pdf_dict *d, stream *source, s
s_CF_set_defaults_inline(&ss);
- if (d && d->type == PDF_DICT) {
+ if (d && pdfi_type_of(d) == PDF_DICT) {
code = pdfi_dict_get_int(ctx, d, "K", &i);
if (code < 0 && code != gs_error_undefined)
return code;
@@ -922,12 +926,11 @@ int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *stream_obj,
goto exit;
}
- if (Filter->type != PDF_ARRAY && Filter->type != PDF_NAME) {
+ switch (pdfi_type_of(Filter)) {
+ default:
code = gs_note_error(gs_error_typecheck);
goto exit;
- }
-
- if (Filter->type == PDF_NAME) {
+ case PDF_NAME:
code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", &decode);
if (code == 0 && inline_image)
code = pdfi_dict_knownget(ctx, stream_dict, "DP", &decode);
@@ -940,7 +943,9 @@ int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *stream_obj,
goto exit;
code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
- } else {
+ break;
+ case PDF_ARRAY:
+ {
pdf_array *filter_array = (pdf_array *)Filter;
code = pdfi_dict_knownget_type(ctx, stream_dict, "DecodeParms", PDF_ARRAY, (pdf_obj **)&DecodeParams);
@@ -1003,11 +1008,15 @@ int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *stream_obj,
goto error;
}
}
- if (decode && decode->type != PDF_NULL && decode->type != PDF_DICT) {
+ if (decode && decode != PDF_NULL_OBJ && pdfi_type_of(decode) != PDF_DICT) {
pdfi_countdown(decode);
decode = NULL;
pdfi_set_warning(ctx, 0, NULL, W_PDF_STREAM_BAD_DECODEPARMS, "pdfi_filter_no_decryption", NULL);
}
+ if (decode && decode == PDF_NULL_OBJ) {
+ pdfi_countdown(decode);
+ decode = NULL;
+ }
code = pdfi_apply_filter(ctx, stream_dict, (pdf_name *)o,
(pdf_dict *)decode, s, &new_s, inline_image);
@@ -1022,6 +1031,7 @@ int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *stream_obj,
}
code = pdfi_alloc_stream(ctx, s, source->s, new_stream);
}
+ }
exit:
pdfi_countdown(o);
@@ -1050,6 +1060,9 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
pdf_c_stream *crypt_stream = NULL, *SubFile_stream = NULL;
pdf_string *StreamKey = NULL;
pdf_dict *stream_dict = NULL;
+ pdf_obj *FileSpec = NULL;
+ pdf_stream *NewStream = NULL;
+ bool known = false;
*new_stream = NULL;
@@ -1057,6 +1070,98 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
if (code < 0)
goto error;
+ /* Horrifyingly, any stream dictionary can contain a file specification, which means that
+ * instead of using the stream from the PDF file we must use an external file.
+ * So much for portability!
+ * Note: We must not do this for inline images as an inline image dictionary can
+ * contain the abbreviation /F for the Filter, and an inline image is never a
+ * separate stream, it is (obviously) contained in the current stream.
+ */
+ if (!inline_image) {
+ code = pdfi_dict_known(ctx, stream_dict, "F", &known);
+ if (code >= 0 && known) {
+ pdf_obj *FS = NULL, *o = NULL;
+ pdf_dict *dict = NULL;
+ stream *gstream = NULL;
+
+ code = pdfi_dict_get(ctx, stream_dict, "F", &FileSpec);
+ if (code < 0)
+ goto error;
+ if (pdfi_type_of(FileSpec) == PDF_DICT) {
+ /* We don't really support FileSpec dictionaries, partly because we
+ * don't really know which platform to use. If there is a /F string
+ * then we will use that, just as if we had been given a string in
+ * the first place.
+ */
+ code = pdfi_dict_knownget(ctx, (pdf_dict *)FileSpec, "F", &FS);
+ if (code < 0) {
+ goto error;
+ }
+ pdfi_countdown(FileSpec);
+ FileSpec = FS;
+ FS = NULL;
+ }
+ if (pdfi_type_of(FileSpec) != PDF_STRING) {
+ code = gs_note_error(gs_error_typecheck);
+ goto error;
+ }
+ /* We should now have a string with the filename (or URL). We need
+ * to open the file and create a stream, if that succeeds.
+ */
+ gstream = sfopen((const char *)((pdf_string *)FileSpec)->data, "r", ctx->memory);
+ if (gstream == NULL) {
+ emprintf1(ctx->memory, "Failed to open file %s\n", (const char *)((pdf_string *)FileSpec)->data);
+ code = gs_note_error(gs_error_ioerror);
+ goto error;
+ }
+
+ source = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "external stream");
+ if (source == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ memset(source, 0x00, sizeof(pdf_c_stream));
+ source->s = gstream;
+
+ code = pdfi_object_alloc(ctx, PDF_STREAM, 0, (pdf_obj **)&NewStream);
+ if (code < 0)
+ goto error;
+ pdfi_countup(NewStream);
+ code = pdfi_dict_alloc(ctx, 32, &dict);
+ if (code < 0){
+ pdfi_countdown(NewStream);
+ goto error;
+ }
+ pdfi_countup(dict);
+ NewStream->stream_dict = dict;
+ code = pdfi_dict_get(ctx, stream_dict, "FFilter", &o);
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, NewStream->stream_dict, "Filter", o);
+ if (code < 0) {
+ pdfi_countdown(NewStream);
+ goto error;
+ }
+ }
+ code = pdfi_dict_get(ctx, stream_dict, "FPredictor", &o);
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, NewStream->stream_dict, "Predictor", o);
+ if (code < 0) {
+ pdfi_countdown(NewStream);
+ goto error;
+ }
+ }
+ pdfi_countup(NewStream->stream_dict);
+ NewStream->stream_offset = 0;
+ NewStream->Length = 0;
+ NewStream->length_valid = 0;
+ NewStream->stream_written = 0;
+ NewStream->is_marking = 0;
+ NewStream->parent_obj = NULL;
+ stream_obj = NewStream;
+ stream_dict = NewStream->stream_dict;
+ }
+ }
+
/* If the file isn't encrypted, don't apply encryption. If this is an inline
* image then its in a content stream and will already be decrypted, so don't
* apply decryption again.
@@ -1143,7 +1248,9 @@ int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source,
code = pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
}
error:
+ pdfi_countdown(NewStream);
pdfi_countdown(StreamKey);
+ pdfi_countdown(FileSpec);
return code;
}
diff --git a/pdf/pdf_fmap.c b/pdf/pdf_fmap.c
index ee05af1c..00034594 100644
--- a/pdf/pdf_fmap.c
+++ b/pdf/pdf_fmap.c
@@ -728,11 +728,11 @@ static int pdfi_generate_native_fontmap(pdf_context *ctx)
(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) {
+ if (pdfi_type_of(v) == 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)
+ if (code >= 0 && pdfi_type_of(n) == PDF_INT)
find = n->value.i;
else
code = 0;
@@ -758,11 +758,11 @@ static int pdfi_generate_native_fontmap(pdf_context *ctx)
(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) {
+ if (pdfi_type_of(v) == 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)
+ if (code >= 0 && pdfi_type_of(n) == PDF_INT)
find = n->value.i;
else
code = 0;
@@ -814,48 +814,56 @@ pdf_fontmap_lookup_font(pdf_context *ctx, pdf_name *fname, pdf_obj **mapname, in
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) {
+ 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;
+ if (code >= 0) {
+ if (pdfi_type_of(record) == PDF_STRING) {
+ mname = record;
+ }
+ else if (pdfi_type_of(record) == PDF_DICT) {
+ int64_t i64;
+ code = pdfi_dict_get(ctx, (pdf_dict *)record, "Path", &mname);
+ if (code >= 0)
+ code = pdfi_dict_get_int(ctx, (pdf_dict *)record, "Index", &i64);
+ if (code < 0) {
+ pdfi_countdown(record);
+ return code;
+ }
+ *findex = (int)i64; /* Rangecheck? */
}
- code = pdfi_dict_get(ctx, (pdf_dict *)record, "Index", (pdf_obj **)&ind);
- if (code >= 0 && ind->type == PDF_INT) {
- *findex = ind->value.i;
+ else {
+ pdfi_countdown(record);
+ code = gs_error_undefined;
}
}
}
+ else {
+ code = gs_error_undefined;
+ }
- if (mname != NULL && mname->type == PDF_STRING && pdfi_fmap_file_exists(ctx, (pdf_string *)mname)) {
+ if (code < 0) {
+ 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;
+ }
+ }
+ }
+ if (mname != NULL && pdfi_type_of(mname) == 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" */
+ else if (mname != NULL && pdfi_type_of(mname) == PDF_NAME) { /* If we map to a name, we assume (for now) we have the font as a "built-in" */
*mapname = mname;
code = 0;
}
@@ -881,9 +889,9 @@ pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name
return code;
}
}
- if (name == NULL || name->type != PDF_NAME) {
+ if (name == NULL || pdfi_type_of(name) != PDF_NAME) {
code = pdfi_dict_get(ctx, font_dict, "BaseFont", &cidname);
- if (code < 0 || cidname->type != PDF_NAME) {
+ if (code < 0 || pdfi_type_of(cidname) != PDF_NAME) {
pdfi_countdown(cidname);
return_error(gs_error_undefined);
}
@@ -910,19 +918,18 @@ pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name
pdfi_countdown(mname);
mname = mname2;
}
- if (mname->type == PDF_DICT) {
+ if (pdfi_type_of(mname) == 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;
+ int64_t i64;
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) {
+ if (code < 0 || pdfi_type_of(filetype) != PDF_NAME || filetype->length != 8 || memcmp(filetype->data, "TrueType", 8) != 0) {
pdfi_countdown(filetype);
pdfi_countdown(rec);
return_error(gs_error_undefined);
@@ -930,21 +937,21 @@ pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name
pdfi_countdown(filetype);
code = pdfi_dict_get(ctx, rec, "CSI", (pdf_obj **)&mcsi);
- if (code < 0 || mcsi->type != PDF_ARRAY) {
+ if (code < 0 || pdfi_type_of(mcsi) != 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) {
+ if (code < 0 || pdfi_type_of(ocsi) != 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) {
+ if (code < 0 || pdfi_type_of(ord1) != PDF_STRING) {
pdfi_countdown(ord1);
pdfi_countdown(ocsi);
pdfi_countdown(mcsi);
@@ -952,7 +959,7 @@ pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name
return_error(gs_error_undefined);
}
code = pdfi_array_get(ctx, mcsi, 0, (pdf_obj **)&ord2);
- if (code < 0 || ord2->type != PDF_STRING) {
+ if (code < 0 || pdfi_type_of(ord2) != PDF_STRING) {
pdfi_countdown(ord1);
pdfi_countdown(ord2);
pdfi_countdown(ocsi);
@@ -970,43 +977,16 @@ pdf_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name
}
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)) {
+ if (code < 0 || pdfi_type_of(path) != 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 = pdfi_dict_get_int(ctx, rec, "Index", &i64);
+ *findex = (code < 0) ? 0 : (int)i64; /* rangecheck? */
code = 0;
}
diff --git a/pdf/pdf_font.c b/pdf/pdf_font.c
index fa716056..28ebe96e 100644
--- a/pdf/pdf_font.c
+++ b/pdf/pdf_font.c
@@ -34,11 +34,14 @@
#include "pdf_font0.h"
#include "pdf_fmap.h"
#include "gscencs.h" /* For gs_c_known_encode and gs_c_glyph_name */
+#include "gsagl.h"
#include "strmio.h"
#include "stream.h"
#include "gsstate.h" /* For gs_setPDFfontsize() */
+extern single_glyph_list_t SingleGlyphList[];
+
static int pdfi_gs_setfont(pdf_context *ctx, gs_font *pfont)
{
int code = 0;
@@ -78,7 +81,7 @@ bool pdfi_font_known_symbolic(pdf_obj *basefont)
int i;
pdf_name *nm = (pdf_name *)basefont;
- if (basefont != NULL && basefont->type == PDF_NAME) {
+ if (basefont != NULL && pdfi_type_of(basefont) == PDF_NAME) {
for (i = 0; known_symbolic_font_names[i].name != NULL; i++) {
if (nm->length == known_symbolic_font_names[i].namelen
&& !strncmp((char *)nm->data, known_symbolic_font_names[i].name, nm->length)) {
@@ -104,7 +107,7 @@ pdfi_font_match_glyph_widths(pdf_font *pdfont)
/* For "best" results, restrict to what we *hope* are A-Z,a-z */
sindex = pdfont->FirstChar < 96 ? 96 : pdfont->FirstChar;
- lindex = pdfont->LastChar > 122 ? 122 : pdfont->LastChar;
+ lindex = pdfont->LastChar > 122 ? 123 : pdfont->LastChar + 1;
for (i = sindex; i < lindex; i++) {
gs_glyph_info_t ginfo = {0};
@@ -156,8 +159,14 @@ static void pdfi_print_font_name(pdf_context *ctx, pdf_name *n)
(void)outwrite(ctx->memory, (const char *)n->data, n->length);
}
+static void pdfi_print_font_string(pdf_context *ctx, pdf_string *s)
+{
+ if (ctx->args.QUIET != true)
+ (void)outwrite(ctx->memory, (const char *)s->data, s->length);
+}
+
/* Print a null terminated string to stdout */
-static void pdfi_print_string(pdf_context *ctx, const char *str)
+static void pdfi_print_cstring(pdf_context *ctx, const char *str)
{
if (ctx->args.QUIET != true)
(void)outwrite(ctx->memory, str, strlen(str));
@@ -169,7 +178,7 @@ static void pdfi_print_string(pdf_context *ctx, const char *str)
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, int *findex)
+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 = 0;
char fontfname[gp_file_name_sizeof];
@@ -184,12 +193,12 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
pdf_dict *csi = NULL;
code = pdfi_dict_get(ctx, font_dict, "CIDSystemInfo", (pdf_obj **)&csi);
- if (code >= 0 && csi->type == PDF_DICT) {
+ if (code >= 0 && pdfi_type_of(csi) == 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
+ && pdfi_type_of(csi_reg) == PDF_STRING && pdfi_type_of(csi_ord) == 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);
@@ -209,10 +218,10 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
}
pdfi_countdown(csi);
- if (mname == NULL || mname->type != PDF_STRING)
+ if (mname == NULL || pdfi_type_of(mname) != PDF_STRING)
code = pdf_fontmap_lookup_cidfont(ctx, font_dict, NULL, (pdf_obj **)&mname, findex);
- if (code < 0 || mname->type != PDF_STRING) {
+ if (code < 0 || pdfi_type_of(mname) != PDF_STRING) {
const char *fsprefix = "CIDFSubst/";
int fsprefixlen = strlen(fsprefix);
const char *defcidfallack = "DroidSansFallback.ttf";
@@ -224,26 +233,26 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
code = gs_note_error(gs_error_invalidfont);
}
else {
- if (ctx->args.cidsubstpath.data == NULL) {
+ if (ctx->args.cidfsubstpath.data == NULL) {
memcpy(fontfname, fsprefix, fsprefixlen);
}
else {
- memcpy(fontfname, ctx->args.cidsubstpath.data, ctx->args.cidsubstpath.size);
- fsprefixlen = ctx->args.cidsubstpath.size;
+ memcpy(fontfname, ctx->args.cidfsubstpath.data, ctx->args.cidfsubstpath.size);
+ fsprefixlen = ctx->args.cidfsubstpath.size;
}
- if (ctx->args.cidsubstfont.data == NULL) {
+ if (ctx->args.cidfsubstfont.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);
+ if (gp_getenv("CIDFSUBSTFONT", (char *)0, &len) < 0 && len + fsprefixlen + 1 < gp_file_name_sizeof) {
+ (void)gp_getenv("CIDFSUBSTFONT", (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;
+ memcpy(fontfname, ctx->args.cidfsubstfont.data, ctx->args.cidfsubstfont.size);
+ defcidfallacklen = ctx->args.cidfsubstfont.size;
}
fontfname[fsprefixlen + defcidfallacklen] = '\0';
@@ -253,12 +262,12 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
}
else {
if (cidname) {
- pdfi_print_string(ctx, "Loading CIDFont ");
+ pdfi_print_cstring(ctx, "Loading CIDFont ");
pdfi_print_font_name(ctx, (pdf_name *)cidname);
- pdfi_print_string(ctx, " substitute from ");
+ pdfi_print_cstring(ctx, " substitute from ");
}
else {
- pdfi_print_string(ctx, "Loading nameless CIDFont from ");
+ pdfi_print_cstring(ctx, "Loading nameless CIDFont from ");
}
sfilename(s, &fname);
if (fname.size < gp_file_name_sizeof) {
@@ -268,8 +277,8 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
else {
strcpy(fontfname, "unnamed file");
}
- pdfi_print_string(ctx, fontfname);
- pdfi_print_string(ctx, "\n");
+ pdfi_print_cstring(ctx, fontfname);
+ pdfi_print_cstring(ctx, "\n");
sfseek(s, 0, SEEK_END);
@@ -287,19 +296,25 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
}
}
else {
- code = pdfi_open_resource_file(ctx, (const char *)mname->data, mname->length, &s);
+ if (mname->length + 1 > gp_file_name_sizeof) {
+ pdfi_countdown(mname);
+ return_error(gs_error_invalidfont);
+ }
+ memcpy(fontfname, mname->data, mname->length);
+ fontfname[mname->length] = '\0';
+ code = pdfi_open_resource_file(ctx, (const char *)fontfname, 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_cstring(ctx, "Loading CIDFont ");
pdfi_print_font_name(ctx, (pdf_name *)cidname);
- pdfi_print_string(ctx, " (or substitute) from ");
+ pdfi_print_cstring(ctx, " (or substitute) from ");
}
else {
- pdfi_print_string(ctx, "Loading nameless CIDFont from ");
+ pdfi_print_cstring(ctx, "Loading nameless CIDFont from ");
}
sfilename(s, &fname);
if (fname.size < gp_file_name_sizeof) {
@@ -309,8 +324,8 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
else {
strcpy(fontfname, "unnamed file");
}
- pdfi_print_string(ctx, fontfname);
- pdfi_print_string(ctx, "\n");
+ pdfi_print_cstring(ctx, fontfname);
+ pdfi_print_cstring(ctx, "\n");
sfseek(s, 0, SEEK_END);
*buflen = sftell(s);
sfseek(s, 0, SEEK_SET);
@@ -329,9 +344,11 @@ pdfi_open_CIDFont_substitute_file(pdf_context * ctx, pdf_dict *font_dict, pdf_di
const char *fsprefix = "CIDFont/";
const int fsprefixlen = strlen(fsprefix);
- if (cidname == NULL || cidname->type != PDF_NAME
- || fsprefixlen + cidname->length >= gp_file_name_sizeof)
+ if (cidname == NULL || pdfi_type_of(cidname) != PDF_NAME
+ || fsprefixlen + cidname->length >= gp_file_name_sizeof) {
+ code = gs_note_error(gs_error_invalidfont);
goto exit;
+ }
memcpy(fontfname, fsprefix, fsprefixlen);
memcpy(fontfname + fsprefixlen, cidname->data, cidname->length);
@@ -428,64 +445,90 @@ static const char *pdfi_clean_font_name(const char *fontname)
return NULL;
}
-static const char *pdfi_font_substitute_by_flags(unsigned int flags)
+static int pdfi_font_substitute_by_flags(pdf_context *ctx, unsigned int flags, char **name, int *namelen)
{
bool fixed = ((flags & pdfi_font_flag_fixed) != 0);
bool serif = ((flags & pdfi_font_flag_serif) != 0);
bool italic = ((flags & pdfi_font_flag_italic) != 0);
bool bold = ((flags & pdfi_font_flag_forcebold) != 0);
+ int code = 0;
- if (fixed) {
+ if (ctx->args.defaultfont_is_name == true && ctx->args.defaultfont.size == 4
+ && !memcmp(ctx->args.defaultfont.data, "None", 4)) {
+ *name = NULL;
+ *namelen = 0;
+ code = gs_error_invalidfont;
+ }
+ else if (ctx->args.defaultfont.data != NULL && ctx->args.defaultfont.size > 0) {
+ *name = (char *)ctx->args.defaultfont.data;
+ *namelen = ctx->args.defaultfont.size;
+ }
+ else if (fixed) {
if (bold) {
if (italic) {
- return "Courier-BoldOblique";
+ *name = (char *)pdfi_base_font_names[3][0];
+ *namelen = strlen(*name);
}
else {
- return "Courier-Bold";
+ *name = (char *)pdfi_base_font_names[1][0];
+ *namelen = strlen(*name);
}
}
else {
if (italic) {
- return "Courier-Oblique";
+ *name = (char *)pdfi_base_font_names[2][0];
+ *namelen = strlen(*name);
}
else {
- return "Courier";
+ *name = (char *)pdfi_base_font_names[0][0];
+ *namelen = strlen(*name);
}
}
}
else if (serif) {
if (bold) {
if (italic) {
- return "Times-BoldItalic";
+ *name = (char *)pdfi_base_font_names[11][0];
+ *namelen = strlen(*name);
}
else {
- return "Times-Bold";
+ *name = (char *)pdfi_base_font_names[9][0];
+ *namelen = strlen(*name);
}
}
else {
if (italic) {
- return "Times-Italic";
+ *name = (char *)pdfi_base_font_names[10][0];
+ *namelen = strlen(*name);
}
else {
- return "Times-Roman";
+ *name = (char *)pdfi_base_font_names[8][0];
+ *namelen = strlen(*name);
}
}
} else {
if (bold) {
if (italic) {
- return "Helvetica-BoldOblique";
+ *name = (char *)pdfi_base_font_names[7][0];
+ *namelen = strlen(*name);
}
else {
- return "Helvetica-Bold";
+ *name = (char *)pdfi_base_font_names[5][0];
+ *namelen = strlen(*name);
}
}
else {
if (italic) {
- return "Helvetica-Oblique";
+ *name = (char *)pdfi_base_font_names[6][0];
+ *namelen = strlen(*name);
+ }
+ else {
+ *name = (char *)pdfi_base_font_names[4][0];
+ *namelen = strlen(*name);
}
}
}
- return "Helvetica"; /* Really shouldn't ever happen */
+ return code;
}
enum {
@@ -524,27 +567,112 @@ static int pdfi_fonttype_picker(byte *buf, int64_t buflen)
#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, int *findex)
+static int pdfi_copy_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont)
+{
+ int code;
+ if (pdfi_type_of(spdffont) != PDF_FONT)
+ return_error(gs_error_typecheck);
+
+ switch(spdffont->pdfi_font_type) {
+ case e_pdf_font_type1:
+ code = pdfi_copy_type1_font(ctx, spdffont, font_dict, tpdffont);
+ break;
+ case e_pdf_font_cff:
+ code = pdfi_copy_cff_font(ctx, spdffont, font_dict, tpdffont);
+ break;
+ case e_pdf_font_truetype:
+ code = pdfi_copy_truetype_font(ctx, spdffont, font_dict, tpdffont);
+ break;
+ default:
+ return_error(gs_error_invalidfont);
+ }
+ return code;
+}
+
+enum {
+ font_embedded = 0,
+ font_from_file = 1,
+ font_substitute = 2
+};
+
+static int pdfi_load_font_buffer(pdf_context *ctx, byte *fbuf, int fbuflen, int fftype, pdf_name *Subtype, int findex, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_dict *font_dict, pdf_font **ppdffont, bool cidfont)
+{
+ int code = gs_error_invalidfont;
+ if (fbuf != NULL) {
+ /* First, see if we can glean the type from the magic number */
+ int sftype = pdfi_fonttype_picker(fbuf, fbuflen);
+ if (sftype == no_type_font) {
+ if (fftype != no_type_font)
+ sftype = fftype;
+ else {
+ /* 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;
+ else if (pdfi_name_is(Subtype, "TrueType"))
+ sftype = tt_font;
+ }
+ }
+ /* fbuf ownership passes to the font loader */
+ switch (sftype) {
+ case type1_font:
+ code = pdfi_read_type1_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, fbuf, fbuflen, ppdffont);
+ fbuf = NULL;
+ break;
+ case cff_font:
+ code = pdfi_read_cff_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, fbuf, fbuflen, cidfont, ppdffont);
+ fbuf = NULL;
+ break;
+ case tt_font:
+ {
+ if (cidfont)
+ 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, findex, ppdffont);
+ fbuf = NULL;
+ }
+ break;
+ default:
+ gs_free_object(ctx->memory, fbuf, "pdfi_load_font_buffer(fbuf)");
+ code = gs_note_error(gs_error_invalidfont);
+ }
+ }
+ return code;
+}
+
+static int pdfi_load_font_file(pdf_context *ctx, int fftype, pdf_name *Subtype, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_dict *font_dict, pdf_dict *fontdesc, bool substitute, pdf_font **ppdffont)
{
int code;
char fontfname[gp_file_name_sizeof];
- pdf_obj *basefont = NULL, *mapname;
+ pdf_obj *basefont = NULL, *mapname = NULL;
pdf_obj *fontname = NULL;
stream *s;
const char *fn;
+ int findex = 0;
+ byte *buf;
+ int buflen;
+ pdf_font *pdffont = NULL;
+ pdf_font *substpdffont = NULL;
+ bool f_retry = true;
code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
- if (code < 0 || basefont == NULL || ((pdf_name *)basefont)->length == 0)
- fallback = true;
+ if (substitute == false && (code < 0 || basefont == NULL || ((pdf_name *)basefont)->length == 0)) {
+ pdfi_countdown(basefont);
+ return_error(gs_error_invalidfont);
+ }
- if (fallback == true) {
- const char *fbname;
+ if (substitute == true) {
+ char *fbname;
+ int fbnamelen;
int64_t flags = 0;
if (fontdesc != NULL) {
(void)pdfi_dict_get_int(ctx, fontdesc, "Flags", &flags);
}
- fbname = pdfi_font_substitute_by_flags((int)flags);
+ code = pdfi_font_substitute_by_flags(ctx, (int)flags, &fbname, &fbnamelen);
+ if (code < 0)
+ return code;
+
code = pdfi_name_alloc(ctx, (byte *)fbname, strlen(fbname), (pdf_obj **) &fontname);
if (code < 0)
return code;
@@ -558,87 +686,166 @@ pdfi_open_font_substitute_file(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *
if (((pdf_name *)fontname)->length < gp_file_name_sizeof) {
memcpy(fontfname, ((pdf_name *)fontname)->data, ((pdf_name *)fontname)->length);
fontfname[((pdf_name *)fontname)->length] = '\0';
- fn = pdfi_clean_font_name(fontfname);
- if (fn != NULL) {
- pdfi_countdown(fontname);
+ pdfi_countdown(fontname);
- code = pdfi_name_alloc(ctx, (byte *)fn, strlen(fn), (pdf_obj **) &fontname);
- if (code < 0)
- return code;
- pdfi_countup(fontname);
- }
- }
- code = pdf_fontmap_lookup_font(ctx, (pdf_name *) fontname, &mapname, findex);
- if (code < 0) {
- mapname = fontname;
- pdfi_countup(mapname);
- code = 0;
+ code = pdfi_name_alloc(ctx, (byte *)fontfname, strlen(fontfname), (pdf_obj **) &fontname);
+ if (code < 0)
+ return code;
+ pdfi_countup(fontname);
}
- 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';
+
+ do {
+ code = pdf_fontmap_lookup_font(ctx, (pdf_name *) fontname, &mapname, &findex);
+ if (code < 0) {
+ if (((pdf_name *)fontname)->length < gp_file_name_sizeof) {
+ memcpy(fontfname, ((pdf_name *)fontname)->data, ((pdf_name *)fontname)->length);
+ fontfname[((pdf_name *)fontname)->length] = '\0';
+ fn = pdfi_clean_font_name(fontfname);
+ if (fn != NULL) {
+ pdfi_countdown(fontname);
+
+ code = pdfi_name_alloc(ctx, (byte *)fn, strlen(fn), (pdf_obj **) &fontname);
+ if (code < 0)
+ return code;
+ pdfi_countup(fontname);
+ }
+ }
+ code = pdf_fontmap_lookup_font(ctx, (pdf_name *) fontname, &mapname, &findex);
+ if (code < 0) {
+ mapname = fontname;
+ pdfi_countup(mapname);
+ code = 0;
+ }
+ }
+ if (pdfi_type_of(mapname) == PDF_NAME || pdfi_type_of(mapname) == 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);
}
- }
- else {
- pdfi_countdown(mapname);
- pdfi_countdown(fontname);
- return_error(gs_error_invalidfileaccess);
- }
- code = pdfi_open_font_file(ctx, fontfname, strlen(fontfname), &s);
+ if (ctx->pdf_substitute_fonts != NULL) {
+ code = pdfi_dict_knownget_type(ctx, ctx->pdf_substitute_fonts, fontfname, PDF_FONT, (pdf_obj **)&pdffont);
+ if (code == 1 && pdffont->filename == NULL) {
+ pdfi_countdown(pdffont);
+ pdffont = NULL;
+ code = 0;
+ }
+ }
+ else
+ code = 0;
+
+ if (code != 1) {
+ code = pdfi_open_font_file(ctx, fontfname, strlen(fontfname), &s);
+ if (code < 0 && f_retry && pdfi_type_of(mapname) == PDF_NAME) {
+ pdfi_countdown(fontname);
+ fontname = mapname;
+ mapname = NULL;
+ f_retry = false;
+ continue;
+ }
+ if (code >= 0) {
+ gs_const_string fname;
+
+ 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");
+ }
+ sfseek(s, 0, SEEK_END);
+ buflen = sftell(s);
+ sfseek(s, 0, SEEK_SET);
+ buf = gs_alloc_bytes(ctx->memory, buflen, "pdfi_open_t1_font_file(buf)");
+ if (buf != NULL) {
+ sfread(buf, 1, buflen, s);
+ }
+ else {
+ code = gs_note_error(gs_error_VMerror);
+ }
+ sfclose(s);
+ /* On success, the buffer owership moves to the font object */
+ code = pdfi_load_font_buffer(ctx, buf, buflen, no_type_font, NULL, findex, stream_dict, page_dict, NULL, &pdffont, false);
+ if (code < 0) {
+ gs_free_object(ctx->memory, buf, "pdfi_load_font_file");
+ }
+ else {
+ pdffont->filename = NULL;
+ code = pdfi_object_alloc(ctx, PDF_STRING, strlen(fontfname) , (pdf_obj **)&pdffont->filename);
+ if (code >= 0) {
+ pdfi_countup(pdffont->filename);
+ memcpy(pdffont->filename->data, fontfname, strlen(fontfname));
+ pdffont->filename->length = strlen(fontfname);
+ }
+
+ if (ctx->pdf_substitute_fonts == NULL) {
+ code = pdfi_dict_alloc(ctx, 16, &ctx->pdf_substitute_fonts);
+ if (code >= 0)
+ pdfi_countup(ctx->pdf_substitute_fonts);
+ }
+ if (ctx->pdf_substitute_fonts != NULL) {
+ if (pdfi_type_of(mapname) == PDF_STRING) {
+ pdf_name *n = NULL;
+ pdf_string *mn = (pdf_string *)mapname;
+
+ code = pdfi_name_alloc(ctx, mn->data, mn->length, (pdf_obj **)&n);
+ if (code >= 0) {
+ pdfi_countdown(mapname);
+ mapname = (pdf_obj *)n;
+ pdfi_countup(mapname);
+ code = 0;
+ }
+ }
+ else
+ code = 0;
+
+ if (code == 0)
+ (void)pdfi_dict_put_obj(ctx, ctx->pdf_substitute_fonts, mapname, (pdf_obj *)pdffont, true);
+ code = 0;
+ }
+ }
+ }
+ }
+ break;
+ } while (1);
+
if (code >= 0) {
- gs_const_string fname;
if (basefont) {
- pdfi_print_string(ctx, "Loading font ");
+ pdfi_print_cstring(ctx, "Loading font ");
pdfi_print_font_name(ctx, (pdf_name *)basefont);
- pdfi_print_string(ctx, " (or substitute) from ");
- }
- else {
- 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';
- }
- 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_t1_font_file(buf)");
- if (*buf != NULL) {
- sfread(*buf, 1, *buflen, s);
+ pdfi_print_cstring(ctx, " (or substitute) from ");
}
else {
- code = gs_note_error(gs_error_VMerror);
+ pdfi_print_cstring(ctx, "Loading nameless font from ");
}
- sfclose(s);
+ pdfi_print_font_string(ctx, pdffont->filename);
+ pdfi_print_cstring(ctx, "\n");
+
+ code = pdfi_copy_font(ctx, pdffont, font_dict, &substpdffont);
+ pdfi_countdown(pdffont);
}
+ *ppdffont = substpdffont;
+
pdfi_countdown(basefont);
pdfi_countdown(mapname);
pdfi_countdown(fontname);
return code;
}
-enum {
- font_embedded = 0,
- font_from_file = 1,
- font_substitute = 2
-};
-
int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_dict *font_dict, gs_font **ppfont, bool cidfont)
{
int code;
@@ -655,13 +862,19 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
int findex = -1;
code = pdfi_dict_get_type(ctx, font_dict, "Type", PDF_NAME, (pdf_obj **)&Type);
- if (code < 0)
- goto exit;
- if (!pdfi_name_is(Type, "Font")){
- code = gs_note_error(gs_error_typecheck);
- goto exit;
+ if (code < 0) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGTYPE, "pdfi_load_font", NULL);
+ }
+ else {
+ if (!pdfi_name_is(Type, "Font")){
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
}
code = pdfi_dict_get_type(ctx, font_dict, "Subtype", PDF_NAME, (pdf_obj **)&Subtype);
+ if (code < 0) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_NO_SUBTYPE, "pdfi_load_font", NULL);
+ }
/* Beyond Type 0 and Type 3, there is no point trusting the Subtype key */
if (code >= 0 && pdfi_name_is(Subtype, "Type0")) {
@@ -682,7 +895,7 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
even if we don't
*/
code = pdfi_dict_get_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj**)&fontdesc);
- if (fontdesc != NULL && fontdesc->type == PDF_DICT) {
+ if (fontdesc != NULL && pdfi_type_of(fontdesc) == PDF_DICT) {
code = pdfi_dict_get_type(ctx, (pdf_dict *) fontdesc, "FontFile", PDF_STREAM, (pdf_obj**)&fontfile);
if (code >= 0)
fftype = type1_font;
@@ -692,7 +905,7 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
}
if (code < 0) {
code = pdfi_dict_get_type(ctx, (pdf_dict *) fontdesc, "FontFile3", PDF_STREAM, (pdf_obj**)&fontfile);
- if (fontfile != NULL) {
+ if (code >= 0 && fontfile != NULL) {
code = pdfi_dict_get_type(ctx, fontfile->stream_dict, "Subtype", PDF_NAME, (pdf_obj **)&ffsubtype);
if (code >= 0) {
if (pdfi_name_is(ffsubtype, "Type1"))
@@ -724,59 +937,27 @@ int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict,
while (1) {
if (fbuf != NULL) {
- /* First, see if we can glean the type from the magic number */
- int sftype = pdfi_fonttype_picker(fbuf, fbuflen);
- if (sftype == no_type_font) {
- if (fftype != no_type_font)
- sftype = fftype;
- else {
- /* 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;
- else if (pdfi_name_is(Subtype, "TrueType"))
- sftype = tt_font;
- }
- }
- /* fbuf ownership passes to the font loader */
- switch (sftype) {
- case type1_font:
- code = pdfi_read_type1_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, fbuf, fbuflen, &ppdffont);
- fbuf = NULL;
- break;
- case cff_font:
- code = pdfi_read_cff_font(ctx, (pdf_dict *)font_dict, stream_dict, page_dict, fbuf, fbuflen, cidfont, &ppdffont);
- fbuf = NULL;
- break;
- case tt_font:
- {
- if (cidfont)
- 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, findex, &ppdffont);
- fbuf = NULL;
- }
- break;
- default:
- code = gs_note_error(gs_error_invalidfont);
- }
+ /* fbuf overship passes to pdfi_load_font_buffer() */
+ code = pdfi_load_font_buffer(ctx, fbuf, fbuflen, fftype, Subtype, findex, stream_dict, page_dict, font_dict, &ppdffont, cidfont);
if (code < 0 && substitute == font_embedded) {
- 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");
+ if (ctx->args.pdfstoponerror == true) {
+ goto exit;
+ }
+ else {
+ char obj[129];
+ pdfi_print_cstring(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_cstring(ctx, obj);
+ pdfi_print_cstring(ctx, "**** Attempting to load a substitute font.\n");
+ }
}
}
+ else {
+ code = gs_error_invalidfont;
+ }
if (code < 0 && code != gs_error_VMerror && substitute == font_embedded) {
- /* Font not embedded, or embedded font not usable - use a substitute */
- if (fbuf != NULL) {
- gs_free_object(ctx->memory, fbuf, "pdfi_load_font(fbuf)");
- }
-
substitute = font_from_file;
if (cidfont == true) {
@@ -790,14 +971,12 @@ 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, &findex);
+ code = pdfi_load_font_file(ctx, no_type_font, Subtype, stream_dict, page_dict, font_dict, fontdesc, false, &ppdffont);
if (code < 0) {
- code = pdfi_open_font_substitute_file(ctx, font_dict, fontdesc, true, &fbuf, &fbuflen, &findex);
+ code = pdfi_load_font_file(ctx, no_type_font, Subtype, stream_dict, page_dict, font_dict, fontdesc, true, &ppdffont);
substitute |= font_substitute;
}
-
- if (code < 0)
- goto exit;
+ break;
}
continue;
}
@@ -834,17 +1013,18 @@ int pdfi_load_dict_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_
gs_font *pfont;
pdf_font *pdfif;
- if (font_dict->type == PDF_FONT) {
- pdfi_countup(font_dict);
- pfont = (gs_font *)((pdf_font *)font_dict)->pfont;
- code = 0;
- }
- else {
- if (font_dict->type != PDF_DICT) {
+ switch (pdfi_type_of(font_dict)) {
+ case PDF_FONT:
+ pdfi_countup(font_dict);
+ pfont = (gs_font *)((pdf_font *)font_dict)->pfont;
+ code = 0;
+ break;
+ case PDF_DICT:
+ code = pdfi_load_font(ctx, stream_dict, page_dict, font_dict, &pfont, false);
+ break;
+ default:
code = gs_note_error(gs_error_typecheck);
goto exit;
- }
- code = pdfi_load_font(ctx, stream_dict, page_dict, font_dict, &pfont, false);
}
if (code < 0)
goto exit;
@@ -869,7 +1049,7 @@ static int pdfi_load_resource_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_
int code;
pdf_dict *font_dict = NULL;
- if (fontname->type != PDF_NAME) {
+ if (pdfi_type_of(fontname) != PDF_NAME) {
/* Passing empty string here should fall back to a default font */
return pdfi_font_set_internal_string(ctx, "", point_size);
}
@@ -922,6 +1102,8 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
i = 0;
while(1) {
+ pdf_obj_type type;
+
if (i + 1>= W->size) break;
code = pdfi_array_get_type(pdffont->ctx, W, i, PDF_INT, (pdf_obj **)&c);
if (code < 0) goto cleanup;
@@ -929,7 +1111,9 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
code = pdfi_array_get(pdffont->ctx, W, i + 1, &o);
if (code < 0) goto cleanup;
- if (o->type == PDF_INT) {
+ type = pdfi_type_of(o);
+ if (type == PDF_INT) {
+ double d;
c2 = (pdf_num *)o;
o = NULL;
if (i + 2 >= W->size){
@@ -939,18 +1123,10 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
break;
}
- code = pdfi_array_get(pdffont->ctx, W, i + 2, (pdf_obj **)&o);
+ code = pdfi_array_get_number(pdffont->ctx, W, i + 2, &d);
if (code < 0) goto cleanup;
- if (o->type != PDF_INT && o->type != PDF_REAL) {
- code = gs_note_error(gs_error_typecheck);
- goto cleanup;
- }
if (cid >= c->value.i && cid <= c2->value.i) {
- if (o->type == PDF_INT)
- widths[GLYPH_W0_WIDTH_INDEX] = (double)((pdf_num *)o)->value.i;
- else
- widths[GLYPH_W0_WIDTH_INDEX] = ((pdf_num *)o)->value.d;
-
+ widths[GLYPH_W0_WIDTH_INDEX] = d;
widths[GLYPH_W0_HEIGHT_INDEX] = 0.0;
/* We countdown and NULL c, c2 and o after exit from the loop
* in order to avoid doing so in the break statements
@@ -961,27 +1137,17 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
i += 3;
pdfi_countdown(c2);
pdfi_countdown(c);
- pdfi_countdown(o);
c = c2 = NULL;
- o = NULL;
continue;
}
}
- else if (o->type == PDF_ARRAY) {
+ else if (type == PDF_ARRAY) {
pdf_array *a = (pdf_array *)o;
o = NULL;
if (cid >= c->value.i && cid < c->value.i + a->size) {
- code = pdfi_array_get(pdffont->ctx, a, cid - c->value.i, (pdf_obj **)&o);
+ code = pdfi_array_get_number(pdffont->ctx, a, cid - c->value.i, &widths[GLYPH_W0_WIDTH_INDEX]);
if (code >= 0) {
pdfi_countdown(a);
- if (o->type == PDF_INT)
- widths[GLYPH_W0_WIDTH_INDEX] = (double)((pdf_num *)o)->value.i;
- else if (o->type == PDF_REAL)
- widths[GLYPH_W0_WIDTH_INDEX] = ((pdf_num *)o)->value.d;
- else {
- code = gs_note_error(gs_error_typecheck);
- goto cleanup;
- }
widths[GLYPH_W0_HEIGHT_INDEX] = 0.0;
/* We countdown and NULL c, c2 and o on exit from the loop
* in order to avoid doing so in the break statements
@@ -991,8 +1157,6 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
}
pdfi_countdown(a);
pdfi_countdown(c);
- pdfi_countdown(o);
- o = NULL;
c = NULL;
i += 2;
continue;
@@ -1016,78 +1180,42 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
widths[GLYPH_W1_V_X_INDEX] = (widths[GLYPH_W0_WIDTH_INDEX] / 2.0);
widths[GLYPH_W1_V_Y_INDEX] = 880.0;
- if (DW2 != NULL && DW2->type == PDF_ARRAY
+ if (DW2 != NULL && pdfi_type_of(DW2) == PDF_ARRAY
&& DW2->size >= 2) {
- pdf_num *w2_0 = NULL, *w2_1 = NULL;
-
- code = pdfi_array_get(pdffont->ctx, (pdf_array *)DW2, 0, (pdf_obj **)&w2_0);
- if (code >= 0 && (w2_0->type == PDF_INT || w2_0->type == PDF_REAL)) {
- code = pdfi_array_get(pdffont->ctx, (pdf_array *)DW2, 1, (pdf_obj **)&w2_1);
- if (code >= 0 && (w2_1->type == PDF_INT || w2_1->type == PDF_REAL)) {
- widths[GLYPH_W1_V_X_INDEX] = widths[GLYPH_W0_WIDTH_INDEX] / 2.0;
- if (w2_0->type == PDF_INT)
- widths[GLYPH_W1_V_Y_INDEX] = (double)w2_0->value.i;
- else
- widths[GLYPH_W1_V_Y_INDEX] = (double)w2_0->value.d;
-
- widths[GLYPH_W1_WIDTH_INDEX] = 0.0;
- if (w2_1->type == PDF_INT)
- widths[GLYPH_W1_HEIGHT_INDEX] = (double)w2_1->value.i;
- else
- widths[GLYPH_W1_HEIGHT_INDEX] = (double)w2_1->value.d;
- }
+ code = pdfi_array_get_number(pdffont->ctx, (pdf_array *)DW2, 0, &widths[GLYPH_W1_V_Y_INDEX]);
+ if (code >= 0)
+ code = pdfi_array_get_number(pdffont->ctx, (pdf_array *)DW2, 1, &widths[GLYPH_W1_HEIGHT_INDEX]);
+ if (code >= 0) {
+ widths[GLYPH_W1_V_X_INDEX] = widths[GLYPH_W0_WIDTH_INDEX] / 2.0;
+ widths[GLYPH_W1_WIDTH_INDEX] = 0.0;
}
- pdfi_countdown(w2_0);
- pdfi_countdown(w2_1);
}
- if (W2 != NULL && W2->type == PDF_ARRAY) {
+ if (W2 != NULL && pdfi_type_of(W2) == PDF_ARRAY) {
i = 0;
while(1) {
+ pdf_obj_type type;
if (i + 1 >= W2->size) break;
(void)pdfi_array_get(pdffont->ctx, W2, i, (pdf_obj **)&c);
- if (c->type != PDF_INT) {
+ if (pdfi_type_of(c) != PDF_INT) {
code = gs_note_error(gs_error_typecheck);
goto cleanup;
}
code = pdfi_array_get(pdffont->ctx, W2, i + 1, (pdf_obj **)&o);
if (code < 0) goto cleanup;
- if (o->type == PDF_INT) {
+ type = pdfi_type_of(o);
+ if (type == PDF_INT) {
if (cid >= c->value.i && cid <= ((pdf_num *)o)->value.i) {
- pdf_num *w1y, *v1x, *v1y;
if (i + 4 >= W2->size) {
/* We countdown and NULL c, and o on exit from the function
* so we don't need to do so in the break statements
*/
break;
}
- (void)pdfi_array_get(pdffont->ctx, W2, i + 1, (pdf_obj **)&w1y);
- (void)pdfi_array_get(pdffont->ctx, W2, i + 1, (pdf_obj **)&v1x);
- (void)pdfi_array_get(pdffont->ctx, W2, i + 1, (pdf_obj **)&v1y);
- if (w1y != NULL && (w1y->type == PDF_INT || w1y->type == PDF_REAL)
- && v1x != NULL && (v1x->type == PDF_INT || v1x->type == PDF_REAL)
- && v1y != NULL && (v1y->type == PDF_INT || v1y->type == PDF_REAL)) {
- widths[GLYPH_W1_WIDTH_INDEX] = 0;
- if (w1y->type == PDF_INT)
- widths[GLYPH_W1_HEIGHT_INDEX] = (double)w1y->value.i;
- else
- widths[GLYPH_W1_HEIGHT_INDEX] = w1y->value.d;
-
- if (v1x->type == PDF_INT)
- widths[GLYPH_W1_V_X_INDEX] = (double)v1x->value.i;
- else
- widths[GLYPH_W1_V_X_INDEX] = v1x->value.d;
-
- if (v1y->type == PDF_INT)
- widths[GLYPH_W1_V_Y_INDEX] = (double)v1y->value.i;
- else
- widths[GLYPH_W1_V_Y_INDEX] = v1y->value.d;
- }
- else
- code = gs_note_error(gs_error_typecheck);
-
- pdfi_countdown(w1y);
- pdfi_countdown(v1x);
- pdfi_countdown(v1y);
+ code = pdfi_array_get_number(pdffont->ctx, W2, i + 1, &widths[GLYPH_W1_HEIGHT_INDEX]);
+ if (code < 0) goto cleanup;
+ code = pdfi_array_get_number(pdffont->ctx, W2, i + 1, &widths[GLYPH_W1_V_X_INDEX]);
+ if (code < 0) goto cleanup;
+ code = pdfi_array_get_number(pdffont->ctx, W2, i + 1, &widths[GLYPH_W1_V_Y_INDEX]);
if (code < 0) goto cleanup;
/* We countdown and NULL c, and o on exit from the function
* so we don't need to do so in the break statements
@@ -1096,43 +1224,26 @@ int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths,
}
i += 5;
}
- else if (o->type == PDF_ARRAY) {
+ else if (type == PDF_ARRAY) {
pdf_array *a = (pdf_array *)o;
int l = a->size - (a->size % 3);
o = NULL;
if (cid >= c->value.i && cid < c->value.i + (l / 3)) {
- pdf_num *w1y = NULL, *v1x = NULL, *v1y = NULL;
int index = (cid - c->value.i) * 3;
- (void)pdfi_array_get(pdffont->ctx, a, index, (pdf_obj **)&w1y);
- (void)pdfi_array_get(pdffont->ctx, a, index + 1, (pdf_obj **)&v1x);
- (void)pdfi_array_get(pdffont->ctx, a, index + 2, (pdf_obj **)&v1y);
- pdfi_countdown(a);
-
- if (w1y != NULL && (w1y->type == PDF_INT || w1y->type == PDF_REAL)
- && v1x != NULL && (v1x->type == PDF_INT || v1x->type == PDF_REAL)
- && v1y != NULL && (v1y->type == PDF_INT || v1y->type == PDF_REAL)) {
- widths[GLYPH_W1_WIDTH_INDEX] = 0.0;
- if (w1y->type == PDF_INT)
- widths[GLYPH_W1_HEIGHT_INDEX] = (double)w1y->value.i;
- else
- widths[GLYPH_W1_HEIGHT_INDEX] = w1y->value.d;
-
- if (v1x->type == PDF_INT)
- widths[GLYPH_W1_V_X_INDEX] = (double)v1x->value.i;
- else
- widths[GLYPH_W1_V_X_INDEX] = v1x->value.d;
-
- if (v1y->type == PDF_INT)
- widths[GLYPH_W1_V_Y_INDEX] = (double)v1y->value.i;
- else
- widths[GLYPH_W1_V_Y_INDEX] = v1y->value.d;
+ code = pdfi_array_get_number(pdffont->ctx, a, index, &widths[GLYPH_W1_HEIGHT_INDEX]);
+ if (code < 0) {
+ pdfi_countdown(a);
+ goto cleanup;
}
- else
- code = gs_note_error(gs_error_typecheck);
- pdfi_countdown(w1y);
- pdfi_countdown(v1x);
- pdfi_countdown(v1y);
+ code = pdfi_array_get_number(pdffont->ctx, a, index + 1, &widths[GLYPH_W1_V_X_INDEX]);
+ if (code < 0) {
+ pdfi_countdown(a);
+ goto cleanup;
+ }
+ code = pdfi_array_get_number(pdffont->ctx, a, index + 2, &widths[GLYPH_W1_V_Y_INDEX]);
+ pdfi_countdown(a);
if (code < 0) goto cleanup;
+
/* We countdown and NULL c, and o on exit from the function
* so we don't need to do so in the break statements
*/
@@ -1176,11 +1287,11 @@ int pdfi_d0(pdf_context *ctx)
goto d0_error;
}
- if (ctx->stack_top[-1]->type != PDF_INT && ctx->stack_top[-1]->type != PDF_REAL) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_INT && pdfi_type_of(ctx->stack_top[-1]) != PDF_REAL) {
code = gs_note_error(gs_error_typecheck);
goto d0_error;
}
- if (ctx->stack_top[-2]->type != PDF_INT && ctx->stack_top[-2]->type != PDF_REAL) {
+ if (pdfi_type_of(ctx->stack_top[-2]) != PDF_INT && pdfi_type_of(ctx->stack_top[-2]) != PDF_REAL) {
code = gs_note_error(gs_error_typecheck);
goto d0_error;
}
@@ -1189,11 +1300,11 @@ int pdfi_d0(pdf_context *ctx)
goto d0_error;
}
- if (ctx->stack_top[-1]->type == PDF_INT)
+ if (pdfi_type_of(ctx->stack_top[-1]) == PDF_INT)
width[0] = (double)((pdf_num *)ctx->stack_top[-1])->value.i;
else
width[0] = ((pdf_num *)ctx->stack_top[-1])->value.d;
- if (ctx->stack_top[-2]->type == PDF_INT)
+ if (pdfi_type_of(ctx->stack_top[-2]) == PDF_INT)
width[1] = (double)((pdf_num *)ctx->stack_top[-1])->value.i;
else
width[1] = ((pdf_num *)ctx->stack_top[-1])->value.d;
@@ -1245,7 +1356,7 @@ d0_error:
int pdfi_d1(pdf_context *ctx)
{
- int code = 0, i, gsave_level;
+ int code = 0, gsave_level;
double wbox[6];
if (ctx->text.inside_CharProc == false)
@@ -1253,21 +1364,9 @@ int pdfi_d1(pdf_context *ctx)
ctx->text.CharProc_d_type = pdf_type3_d1;
- if (pdfi_count_stack(ctx) < 6) {
- code = gs_note_error(gs_error_stackunderflow);
+ code = pdfi_destack_reals(ctx, wbox, 6);
+ if (code < 0)
goto d1_error;
- }
-
- for (i=-6;i < 0;i++) {
- if (ctx->stack_top[i]->type != PDF_INT && ctx->stack_top[i]->type != PDF_REAL) {
- code = gs_note_error(gs_error_typecheck);
- goto d1_error;
- }
- if (ctx->stack_top[i]->type == PDF_INT)
- wbox[i + 6] = (double)((pdf_num *)ctx->stack_top[i])->value.i;
- else
- wbox[i + 6] = ((pdf_num *)ctx->stack_top[i])->value.d;
- }
/*
* We don't intend to retain this, instead we will use (effectively) xyshow to apply
@@ -1291,7 +1390,6 @@ int pdfi_d1(pdf_context *ctx)
if (code < 0)
goto d1_error;
- pdfi_pop(ctx, 6);
return 0;
d1_error:
@@ -1319,16 +1417,9 @@ int pdfi_Tf(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
pdfi_pop(ctx, 2);
/* Get the point_size */
- if (point_arg->type == PDF_INT)
- point_size = (double)((pdf_num *)point_arg)->value.i;
- else {
- if (point_arg->type == PDF_REAL)
- point_size = ((pdf_num *)point_arg)->value.d;
- else {
- code = gs_note_error(gs_error_typecheck);
- goto exit0;
- }
- }
+ code = pdfi_obj_to_real(ctx, point_arg, &point_size);
+ if (code < 0)
+ goto exit0;
code = pdfi_load_resource_font(ctx, stream_dict, page_dict, fontname, point_size);
@@ -1378,7 +1469,7 @@ int pdfi_free_font(pdf_obj *font)
static inline int pdfi_encoding_name_to_index(pdf_name *name)
{
int ind = gs_error_undefined;
- if (name->type == PDF_NAME) {
+ if (pdfi_type_of(name) == PDF_NAME) {
if (pdfi_name_is(name, "StandardEncoding")) {
ind = ENCODING_INDEX_STANDARD;
} else {
@@ -1452,21 +1543,23 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
return code;
pdfi_countup(*Encoding);
- if (pdf_Encoding->type == PDF_NAME) {
- code = pdfi_build_Encoding(ctx, (pdf_name *)pdf_Encoding, (pdf_array *)*Encoding);
- if (code < 0) {
- pdfi_countdown(*Encoding);
- *Encoding = NULL;
- return code;
- }
- } else {
- if (pdf_Encoding->type == PDF_DICT) {
+ switch (pdfi_type_of(pdf_Encoding)) {
+ case PDF_NAME:
+ code = pdfi_build_Encoding(ctx, (pdf_name *)pdf_Encoding, (pdf_array *)*Encoding);
+ if (code < 0) {
+ pdfi_countdown(*Encoding);
+ *Encoding = NULL;
+ return code;
+ }
+ break;
+ case PDF_DICT:
+ {
pdf_name *n = NULL;
pdf_array *a = NULL;
pdf_obj *o = NULL;
int offset = 0;
- if (font_Encoding != NULL && font_Encoding->type == PDF_ARRAY) {
+ if (font_Encoding != NULL && pdfi_type_of(font_Encoding) == PDF_ARRAY) {
pdf_array *fenc = (pdf_array *)font_Encoding;
for (i = 0; i < pdfi_array_size(fenc) && code >= 0; i++) {
code = pdfi_array_get(ctx, fenc, (uint64_t)i, &o);
@@ -1523,25 +1616,25 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
}
for (i=0;i < pdfi_array_size(a);i++) {
+ pdf_obj_type type;
code = pdfi_array_get(ctx, a, (uint64_t)i, &o);
if (code < 0)
break;
- if (o->type == PDF_NAME) {
+ type = pdfi_type_of(o);
+ if (type == PDF_NAME) {
if (offset < pdfi_array_size((pdf_array *)*Encoding))
code = pdfi_array_put(ctx, (pdf_array *)*Encoding, (uint64_t)offset, o);
pdfi_countdown(o);
offset++;
if (code < 0)
break;
+ } else if (type == PDF_INT) {
+ offset = ((pdf_num *)o)->value.i;
+ pdfi_countdown(o);
} else {
- if (o->type == PDF_INT) {
- offset = ((pdf_num *)o)->value.i;
- pdfi_countdown(o);
- } else {
- code = gs_note_error(gs_error_typecheck);
- pdfi_countdown(o);
- break;
- }
+ code = gs_note_error(gs_error_typecheck);
+ pdfi_countdown(o);
+ break;
}
}
pdfi_countdown(a);
@@ -1550,11 +1643,12 @@ int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_
*Encoding = NULL;
return code;
}
- } else {
+ break;
+ }
+ default:
pdfi_countdown(*Encoding);
*Encoding = NULL;
return gs_note_error(gs_error_typecheck);
- }
}
return 0;
}
@@ -1575,6 +1669,10 @@ gs_glyph pdfi_encode_char(gs_font * pfont, gs_char chr, gs_glyph_space_t not_use
pdf_name *GlyphName = NULL;
code = pdfi_array_get(ctx, font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName);
if (code >= 0) {
+ if (pdfi_type_of(GlyphName) != PDF_NAME)
+ /* Can't signal an error, just return the 'not found' case */
+ return g;
+
code = (*ctx->get_glyph_index)(pfont, (byte *)GlyphName->data, GlyphName->length, &nindex);
pdfi_countdown(GlyphName);
if (code >= 0)
@@ -1595,9 +1693,9 @@ int pdfi_tounicode_char_to_unicode(pdf_context *ctx, pdf_cmap *tounicode, gs_gly
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) {
+ while (l == 0 && 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)) {
+ while (l == 0 && 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++) {
@@ -1704,6 +1802,62 @@ static int pdfi_global_glyph_code(const gs_font *pfont, gs_const_string *gstr, g
return code;
}
+int pdfi_map_glyph_name_via_agl(pdf_dict *cstrings, pdf_name *gname, pdf_string **cstring)
+{
+ single_glyph_list_t *sgl = (single_glyph_list_t *)&(SingleGlyphList);
+ int i, code, ucode = gs_error_undefined;
+ *cstring = NULL;
+
+ if (gname->length == 7 && strncmp((char *)gname->data, "uni", 3) == 0) {
+ char u[5] = {0};
+ memcpy(u, gname->data + 3, 4);
+ code = sscanf(u, "%x", &ucode);
+ if (code <= 0)
+ ucode = gs_error_undefined;
+ }
+
+ if (ucode == gs_error_undefined) {
+ for (i = 0; sgl[i].Glyph != 0x00; i++) {
+ if (sgl[i].Glyph[0] == gname->data[0]
+ && strlen(sgl[i].Glyph) == gname->length
+ && !strncmp((char *)sgl[i].Glyph, (char *)gname->data, gname->length)) {
+ ucode = (int)sgl[i].Unicode;
+ break;
+ }
+ }
+ }
+ if (ucode > 0) {
+ for (i = 0; sgl[i].Glyph != 0x00; i++) {
+ if (sgl[i].Unicode == (unsigned short)ucode) {
+ pdf_string *s;
+ code = pdfi_dict_get((pdf_context *)cstrings->ctx, cstrings, (char *)sgl[i].Glyph, (pdf_obj **)&s);
+ if (code >= 0) {
+ *cstring = s;
+ break;
+ }
+ }
+ }
+ if (*cstring == NULL) {
+ char u[16] = {0};
+ code = gs_snprintf(u, 16, "uni%04x", ucode);
+ if (code > 0) {
+ pdf_string *s;
+ code = pdfi_dict_get((pdf_context *)cstrings->ctx, cstrings, u, (pdf_obj **)&s);
+ if (code >= 0) {
+ *cstring = s;
+ }
+ }
+ }
+ }
+
+ if (*cstring == NULL)
+ code = gs_note_error(gs_error_undefined);
+ else
+ code = 0;
+
+ return code;
+}
+
int pdfi_init_font_directory(pdf_context *ctx)
{
ctx->font_dir = gs_font_dir_alloc2(ctx->memory, ctx->memory);
@@ -1763,6 +1917,95 @@ int pdfi_load_font_by_name_string(pdf_context *ctx, const byte *fontname, size_t
return code;
}
+
+int pdfi_font_create_widths(pdf_context *ctx, pdf_dict *fontdict, pdf_font *font, double scale)
+{
+ int code = 0;
+ pdf_obj *obj = NULL;
+ int i;
+
+ font->Widths = NULL;
+
+ if (font->FontDescriptor != NULL) {
+ code = pdfi_dict_knownget(ctx, font->FontDescriptor, "MissingWidth", &obj);
+ if (code > 0) {
+ if (pdfi_type_of(obj) == PDF_INT) {
+ font->MissingWidth = ((pdf_num *) obj)->value.i * scale;
+ }
+ else if (pdfi_type_of(obj) == PDF_REAL) {
+ font->MissingWidth = ((pdf_num *) obj)->value.d * scale;
+ }
+ else {
+ font->MissingWidth = 0;
+ }
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
+ else {
+ font->MissingWidth = 0;
+ }
+ }
+ else {
+ font->MissingWidth = 1000.0 * scale;
+ }
+
+ code = pdfi_dict_knownget_type(ctx, fontdict, "Widths", PDF_ARRAY, (pdf_obj **)&obj);
+ if (code > 0) {
+ if (pdfi_array_size((pdf_array *)obj) < font->LastChar - font->FirstChar + 1) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto error;
+ }
+
+ font->Widths = (double *)gs_alloc_bytes(OBJ_MEMORY(font), sizeof(double) * (font->LastChar - font->FirstChar + 1), "pdfi_font_create_widths(Widths)");
+ if (font->Widths == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ memset(font->Widths, 0x00, sizeof(double) * (font->LastChar - font->FirstChar + 1));
+ for (i = 0; i < (font->LastChar - font->FirstChar + 1); i++) {
+ code = pdfi_array_get_number(ctx, (pdf_array *)obj, (uint64_t)i, &font->Widths[i]);
+ if (code < 0)
+ goto error;
+ font->Widths[i] *= scale;
+ }
+ }
+error:
+ pdfi_countdown(obj);
+ if (code < 0) {
+ gs_free_object(OBJ_MEMORY(font), font->Widths, "pdfi_font_create_widths(Widths)");
+ font->Widths = NULL;
+ }
+ return code;
+}
+
+void pdfi_font_set_first_last_char(pdf_context *ctx, pdf_dict *fontdict, pdf_font *font)
+{
+ double f, l;
+ int code;
+
+ if (fontdict == NULL) {
+ f = (double)0;
+ l = (double)255;
+ }
+ else {
+ code = pdfi_dict_get_number(ctx, fontdict, "FirstChar", &f);
+ if (code < 0 || f < 0 || f > 255)
+ f = (double)0;
+
+ code = pdfi_dict_get_number(ctx, fontdict, "LastChar", &l);
+ if (code < 0 || l < 0 || l > 255)
+ l = (double)255;
+ }
+ if (f <= l) {
+ font->FirstChar = f;
+ font->LastChar = l;
+ }
+ else {
+ font->FirstChar = 0;
+ font->LastChar = 255;
+ }
+}
+
/* Patch or create a new XUID based on the existing UID/XUID, a simple hash
of the input file name and the font dictionary object number.
This allows improved glyph cache efficiency, also ensures pdfwrite understands
@@ -1776,10 +2019,10 @@ int pdfi_font_generate_pseudo_XUID(pdf_context *ctx, pdf_dict *fontdict, gs_font
int i;
uint32_t hash = 0;
long *xvalues;
- int xuidlen = 2;
+ int xuidlen = 3;
sfilename(ctx->main_stream->s, &fn);
- if (fn.size > 0 && fontdict->object_num != 0) {
+ if (fn.size > 0 && fontdict!= NULL && fontdict->object_num != 0) {
for (i = 0; i < fn.size; i++) {
hash = ((((hash & 0xf8000000) >> 27) ^ (hash << 5)) & 0x7ffffffff) ^ fn.data[i];
}
@@ -1795,14 +2038,17 @@ int pdfi_font_generate_pseudo_XUID(pdf_context *ctx, pdf_dict *fontdict, gs_font
}
xvalues[0] = 1000000; /* "Private" value */
xvalues[1] = hash;
+
+ xvalues[2] = ctx->device_state.HighLevelDevice ? pfont->id : 0;
+
if (uid_is_XUID(&pfont->UID)) {
for (i = 0; i < uid_XUID_size(&pfont->UID); i++) {
- xvalues[i + 2] = uid_XUID_values(&pfont->UID)[i];
+ xvalues[i + 3] = uid_XUID_values(&pfont->UID)[i];
}
uid_free(&pfont->UID, pfont->memory, "pdfi_font_generate_pseudo_XUID");
}
else if (uid_is_valid(&pfont->UID))
- xvalues[2] = pfont->UID.id;
+ xvalues[3] = pfont->UID.id;
uid_set_XUID(&pfont->UID, xvalues, xuidlen);
}
@@ -1817,7 +2063,7 @@ int pdfi_set_font_internal(pdf_context *ctx, pdf_obj *fontobj, double point_size
int code;
pdf_font *pdffont = (pdf_font *)fontobj;
- if (pdffont->type != PDF_FONT || pdffont->pfont == NULL)
+ if (pdfi_type_of(pdffont) != PDF_FONT || pdffont->pfont == NULL)
return_error(gs_error_invalidfont);
code = gs_setPDFfontsize(ctx->pgs, point_size);
@@ -1854,7 +2100,7 @@ int pdfi_font_set_internal_string(pdf_context *ctx, const char *fontname, double
int pdfi_font_set_internal_name(pdf_context *ctx, pdf_name *fontname, double point_size)
{
- if (fontname->type != PDF_NAME)
+ if (pdfi_type_of(fontname) != PDF_NAME)
return_error(gs_error_typecheck);
else
return pdfi_font_set_internal_inner(ctx, fontname->data, fontname->length, point_size);
diff --git a/pdf/pdf_font.h b/pdf/pdf_font.h
index da76aeb8..a18541c6 100644
--- a/pdf/pdf_font.h
+++ b/pdf/pdf_font.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
@@ -57,6 +57,7 @@ static inline pdf_font *pdfi_get_current_pdf_font(pdf_context *ctx)
return NULL;
}
+int pdfi_create_Widths(pdf_context *ctx, pdf_dict *font_dict, pdf_font *pdffont);
int pdfi_create_Encoding(pdf_context *ctx, pdf_obj *pdf_Encoding, pdf_obj *font_Encoding, pdf_obj **Encoding);
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);
@@ -72,6 +73,8 @@ int pdfi_fapi_passfont(pdf_font *font, int subfont, char *fapi_request,
int pdfi_fapi_check_cmap_for_GID(gs_font *pfont, uint c, uint *g);
+int pdfi_map_glyph_name_via_agl(pdf_dict *cstrings, pdf_name *gname, pdf_string **cstring);
+
int pdfi_init_font_directory(pdf_context *ctx);
int pdfi_load_font(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_dict *font_dict, gs_font **ppfont, bool cidfont);
@@ -103,5 +106,7 @@ enum {
};
int pdfi_get_cidfont_glyph_metrics(gs_font *pfont, gs_glyph cid, double *widths, bool vertical);
+int pdfi_font_create_widths(pdf_context *ctx, pdf_dict *fontdict, pdf_font *font, double wscale);
+void pdfi_font_set_first_last_char(pdf_context *ctx, pdf_dict *fontdict, pdf_font *font);
int pdfi_font_generate_pseudo_XUID(pdf_context *ctx, pdf_dict *fontdict, gs_font_base *pfont);
#endif
diff --git a/pdf/pdf_font0.c b/pdf/pdf_font0.c
index a322bfb4..76a94c8a 100644
--- a/pdf/pdf_font0.c
+++ b/pdf/pdf_font0.c
@@ -64,9 +64,21 @@ static void pdfi_font0_cid_subst_tables(const char *reg, const int reglen, const
}
static int
-pdfi_font0_glyph_name(gs_font *font, gs_glyph index, gs_const_string *pstr)
+pdfi_font0_glyph_name(gs_font *pfont, gs_glyph index, gs_const_string *pstr)
{
- return_error(gs_error_rangecheck);
+ int code;
+ pdf_font_type0 *pt0font = (pdf_font_type0 *)pfont->client_data;
+ char gnm[64];
+ pdf_context *ctx = pt0font->ctx;
+ uint gindex = 0;
+
+ gs_snprintf(gnm, 64, "%lu", (long)index);
+ code = (*ctx->get_glyph_index)((gs_font *)pfont, (byte *)gnm, strlen(gnm), &gindex);
+ if (code < 0)
+ return code;
+ code = (*ctx->get_glyph_name)(pfont, (gs_glyph)gindex, (gs_const_string *)pstr);
+
+ return code;
}
static int
@@ -80,7 +92,7 @@ pdfi_font0_map_glyph_to_unicode(gs_font *font, gs_glyph glyph, int ch, ushort *u
pdfi_cid_subst_nwp_table_t *substnwp = pt0font->substnwp;
code = pdfi_array_get(pt0font->ctx, pt0font->DescendantFonts, 0, (pdf_obj **)&decfont);
- if (code < 0 || decfont->type != PDF_FONT) {
+ if (code < 0 || pdfi_type_of(decfont) != PDF_FONT) {
pdfi_countdown(decfont);
return gs_error_undefined;
}
@@ -189,7 +201,7 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
code = pdfi_dict_get(ctx, font_dict, "Encoding", &cmap);
if (code < 0) goto error;
- if (cmap->type == PDF_CMAP) {
+ if (pdfi_type_of(cmap) == PDF_CMAP) {
pcmap = (pdf_cmap *)cmap;
cmap = NULL;
}
@@ -203,7 +215,7 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
code = pdfi_dict_get(ctx, font_dict, "DescendantFonts", (pdf_obj **)&arr);
if (code < 0) goto error;
- if (arr->type != PDF_ARRAY || arr->size != 1) {
+ if (pdfi_type_of(arr) != PDF_ARRAY || arr->size != 1) {
code = gs_note_error(gs_error_invalidfont);
goto error;
}
@@ -211,31 +223,32 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
pdfi_countdown(arr);
arr = NULL;
if (code < 0) goto error;
- if (decfontdict->type == PDF_FONT) {
- descpfont = (pdf_font *)decfontdict;
- decfontdict = descpfont->PDF_font;
- pdfi_countup(decfontdict);
- }
- else {
- if (decfontdict->type != PDF_DICT) {
- code = gs_note_error(gs_error_invalidfont);
- goto error;
- }
- code = pdfi_dict_get(ctx, (pdf_dict *)decfontdict, "Type", (pdf_obj **)&n);
- if (code < 0) goto error;
- if (n->type != PDF_NAME || n->length != 4 || memcmp(n->data, "Font", 4) != 0) {
+ switch (pdfi_type_of(decfontdict)) {
+ case PDF_FONT:
+ descpfont = (pdf_font *)decfontdict;
+ decfontdict = descpfont->PDF_font;
+ pdfi_countup(decfontdict);
+ break;
+ case PDF_DICT:
+ code = pdfi_dict_get(ctx, (pdf_dict *)decfontdict, "Type", (pdf_obj **)&n);
+ if (code < 0) goto error;
+ if (pdfi_type_of(n) != PDF_NAME || n->length != 4 || memcmp(n->data, "Font", 4) != 0) {
+ pdfi_countdown(n);
+ code = gs_note_error(gs_error_invalidfont);
+ goto error;
+ }
pdfi_countdown(n);
+ break;
+ default:
code = gs_note_error(gs_error_invalidfont);
goto error;
- }
- pdfi_countdown(n);
}
#if 0
code = pdfi_dict_get(ctx, (pdf_dict *)decfontdict, "Subtype", (pdf_obj **)&n);
if (code < 0)
goto error;
- if (n->type != PDF_NAME || n->length != 12 || memcmp(n->data, "CIDFontType", 11) != 0) {
+ if (pdfi_type_of(n) != PDF_NAME || n->length != 12 || memcmp(n->data, "CIDFontType", 11) != 0) {
pdfi_countdown(n);
code = gs_note_error(gs_error_invalidfont);
goto error;
@@ -255,13 +268,13 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
if (ctx->args.ignoretounicode != true) {
code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
+ if (code >= 0 && pdfi_type_of(tounicode) == 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)) {
+ if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
pdfi_countdown(tounicode);
tounicode = NULL;
code = 0;
@@ -295,8 +308,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 && reg->type == PDF_STRING
- && ord != NULL && ord->type == PDF_STRING) {
+ if (reg != NULL && pdfi_type_of(reg) == PDF_STRING
+ && ord != NULL && pdfi_type_of(ord) == PDF_STRING) {
r = (char *)reg->data;
rlen = reg->length;
o = (char *)ord->data;
@@ -352,6 +365,7 @@ int pdfi_read_type0_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", pdft0->type, pdft0->UID);
#endif
pdft0->refcnt = 1;
+ pdft0->filename = NULL;
pdft0->object_num = font_dict->object_num;
pdft0->generation_num = font_dict->generation_num;
pdft0->indirect_num = font_dict->indirect_num;
@@ -524,6 +538,8 @@ pdfi_free_font_type0(pdf_obj *font)
pdfi_countdown(pdft0->Encoding);
pdfi_countdown(pdft0->DescendantFonts);
pdfi_countdown(pdft0->ToUnicode);
+ pdfi_countdown(pdft0->filename);
+
gs_free_object(OBJ_MEMORY(pdft0), pfont0->data.Encoding, "pdfi_free_font_type0(data.Encoding)");
/* We shouldn't need to free the fonts in the FDepVector, that should happen
with DescendantFonts above.
diff --git a/pdf/pdf_font1.c b/pdf/pdf_font1.c
index 87ba858b..b350f449 100644
--- a/pdf/pdf_font1.c
+++ b/pdf/pdf_font1.c
@@ -117,6 +117,9 @@ pdfi_t1_glyph_data(gs_font_type1 *pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
if (code >= 0) {
code = pdfi_dict_get_by_key(ctx, pdffont1->CharStrings, glyphname, (pdf_obj **)&charstring);
+ if (code < 0) {
+ code = pdfi_map_glyph_name_via_agl(pdffont1->CharStrings, glyphname, &charstring);
+ }
if (code >= 0)
gs_glyph_data_from_bytes(pgd, charstring->data, 0, charstring->length, NULL);
}
@@ -132,11 +135,17 @@ pdfi_t1_subr_data(gs_font_type1 *pfont, int index, bool global, gs_glyph_data_t
int code = 0;
pdf_font_type1 *pdffont1 = (pdf_font_type1 *) pfont->client_data;
- if (global == true || index < 0 || index >= pdffont1->NumSubrs) {
+ if (global == true || index < 0 || index >= (pdffont1->Subrs == NULL ? 0 : pdfi_array_size(pdffont1->Subrs))) {
code = gs_note_error(gs_error_rangecheck);
}
else {
- gs_glyph_data_from_bytes(pgd, pdffont1->Subrs[index].data, 0, pdffont1->Subrs[index].size, NULL);
+ pdf_string *subr_str = NULL;
+ code = pdfi_array_get_type(pdffont1->ctx, pdffont1->Subrs, index, PDF_STRING, (pdf_obj **)&subr_str);
+ if (code >= 0) {
+ gs_glyph_data_from_bytes(pgd, subr_str->data, 0, subr_str->length, NULL);
+ }
+ /* decrementing is safe here, because the reference in the pdffont1->Subrs will persist */
+ pdfi_countdown(subr_str);
}
return code;
}
@@ -168,11 +177,13 @@ pdfi_t1_seac_data(gs_font_type1 *pfont, int ccode, gs_glyph *pglyph, gs_const_st
pdfi_countup(glyphname);
code = pdfi_dict_get_by_key(ctx, pdffont1->CharStrings, glyphname, (pdf_obj **)&charstring);
pdfi_countdown(glyphname);
- if (code >= 0)
- if (pgd != NULL)
+ if (code >= 0) {
+ if (pgd != NULL) {
gs_glyph_data_from_bytes(pgd, charstring->data, 0, charstring->length, NULL);
+ }
pdfi_countdown(charstring);
}
+ }
}
return code;
@@ -368,7 +379,7 @@ pdfi_t1_decode_pfb(pdf_context *ctx, byte *inbuf, int inlen, byte **outbuf, int
*outbuf = NULL;
*outlen = 0;
- strm = push_pfb_filter(ctx->memory, inbuf, inbuf + inlen + 1);
+ strm = push_pfb_filter(ctx->memory, inbuf, inbuf + inlen);
if (strm == NULL) {
code = gs_note_error(gs_error_VMerror);
}
@@ -386,7 +397,7 @@ pdfi_t1_decode_pfb(pdf_context *ctx, byte *inbuf, int inlen, byte **outbuf, int
}
else {
d = decodebuf;
- strm = push_pfb_filter(ctx->memory, inbuf, inbuf + inlen + 1);
+ strm = push_pfb_filter(ctx->memory, inbuf, inbuf + inlen);
while (1) {
c = sgetc(strm);
if (c < 0)
@@ -501,6 +512,7 @@ int
pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *fbuf, int64_t fbuflen, pdf_font **ppdffont)
{
int code = 0;
+ double x_scale;
pdf_obj *fontdesc = NULL;
pdf_obj *basefont = NULL;
pdf_obj *mapname = NULL;
@@ -508,8 +520,10 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pdf_font_type1 *t1f = NULL;
pdf_obj *tounicode = NULL;
ps_font_interp_private fpriv = { 0 };
+ bool key_known;
- (void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
+ if (font_dict != NULL)
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
if (fbuf[0] == 128 && fbuf[1] == 1) {
byte *decodebuf = NULL;
@@ -530,12 +544,12 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
gs_free_object(ctx->memory, fbuf, "pdfi_read_type1_font");
/* If we have a full CharStrings dictionary, we probably have enough to make a font */
- if (code < 0 || (fpriv.u.t1.CharStrings == NULL || fpriv.u.t1.CharStrings->type != PDF_DICT
- || fpriv.u.t1.CharStrings->entries == 0)) {
+ if (code < 0 || fpriv.u.t1.CharStrings == NULL || pdfi_type_of(fpriv.u.t1.CharStrings) != PDF_DICT
+ || fpriv.u.t1.CharStrings->entries == 0) {
code = gs_note_error(gs_error_invalidfont);
goto error;
}
- code = pdfi_alloc_t1_font(ctx, &t1f, font_dict->object_num);
+ code = pdfi_alloc_t1_font(ctx, &t1f, font_dict != NULL ? font_dict->object_num : 0);
if (code >= 0) {
gs_font_type1 *pfont1 = (gs_font_type1 *) t1f->pfont;
@@ -555,22 +569,26 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pfont1->PaintType = fpriv.gsu.gst1.PaintType;
pfont1->StrokeWidth = fpriv.gsu.gst1.StrokeWidth;
- 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;
+ if (font_dict != NULL) {
+ 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;
- pdfi_countup(basefont);
t1f->FontDescriptor = (pdf_dict *) fontdesc;
pdfi_countup(fontdesc);
t1f->Name = mapname;
pdfi_countup(mapname);
/* We want basefont, but we can live without it */
- (void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
+ if (font_dict != NULL) {
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
+ t1f->BaseFont = basefont;
+ pdfi_countup(basefont);
+ }
t1f->descflags = 0;
if (t1f->FontDescriptor != NULL) {
@@ -588,15 +606,15 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->descflags |= 4;
}
- if (ctx->args.ignoretounicode != true) {
+ if (ctx->args.ignoretounicode != true && font_dict != NULL) {
code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
+ if (code >= 0 && pdfi_type_of(tounicode) == 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)) {
+ if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
pdfi_countdown(tounicode);
tounicode = NULL;
code = 0;
@@ -608,74 +626,29 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
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;
- pdfi_countdown(tmp);
- tmp = NULL;
- }
- else {
- t1f->FirstChar = 0;
- }
- code = pdfi_dict_knownget_type(ctx, font_dict, "LastChar", PDF_INT, &tmp);
- if (code == 1) {
- t1f->LastChar = ((pdf_num *) tmp)->value.i;
- pdfi_countdown(tmp);
- tmp = NULL;
- }
- else {
- t1f->LastChar = 255;
- }
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)t1f);
- t1f->fake_glyph_names = (gs_string *) gs_alloc_bytes(ctx->memory, t1f->LastChar * sizeof(gs_string), "pdfi_read_type1_font: fake_glyph_names");
- if (!t1f->fake_glyph_names) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
- memset(t1f->fake_glyph_names, 0x00, t1f->LastChar * sizeof(gs_string));
-
- code = pdfi_dict_knownget_type(ctx, font_dict, "Widths", PDF_ARRAY, &tmp);
- if (code > 0) {
- int i;
- double x_scale;
- int num_chars = t1f->LastChar - t1f->FirstChar + 1;
-
- if (num_chars == pdfi_array_size((pdf_array *) tmp)) {
- t1f->Widths = (double *)gs_alloc_bytes(ctx->memory, sizeof(double) * num_chars, "Type 1 font Widths array");
- if (t1f->Widths == NULL) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
-
- /* Widths are defined assuming a 1000x1000 design grid, but we apply
- * them in font space - so undo the 1000x1000 scaling, and apply
- * the inverse of the font's x scaling
- */
- x_scale = 0.001 / hypot(pfont1->FontMatrix.xx, pfont1->FontMatrix.xy);
-
- memset(t1f->Widths, 0x00, sizeof(double) * num_chars);
- for (i = 0; i < num_chars; i++) {
- code = pdfi_array_get_number(ctx, (pdf_array *) tmp, (uint64_t) i, &t1f->Widths[i]);
- if (code < 0)
- goto error;
- t1f->Widths[i] *= x_scale;
- }
- }
- else {
- t1f->Widths = NULL;
- }
- }
- pdfi_countdown(tmp);
- tmp = NULL;
+ /* Widths are defined assuming a 1000x1000 design grid, but we apply
+ * them in font space - so undo the 1000x1000 scaling, and apply
+ * the inverse of the font's x scaling
+ */
+ x_scale = 0.001 / hypot(pfont1->FontMatrix.xx, pfont1->FontMatrix.xy);
+
+ /* ignore errors with widths... for now */
+ if (font_dict != NULL)
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)t1f, x_scale);
- code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ if (font_dict != NULL)
+ code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ else
+ code = gs_error_undefined;
if (code == 1) {
- if ((tmp->type == PDF_NAME || tmp->type == PDF_DICT) && (t1f->descflags & 4) == 0) {
+ if ((pdfi_type_of(tmp) == PDF_NAME || pdfi_type_of(tmp) == PDF_DICT) && (t1f->descflags & 4) == 0) {
code = pdfi_create_Encoding(ctx, tmp, NULL, (pdf_obj **) & t1f->Encoding);
if (code >= 0)
code = 1;
}
- else if (tmp->type == PDF_DICT && (t1f->descflags & 4) != 0) {
+ else if (pdfi_type_of(tmp) == PDF_DICT && (t1f->descflags & 4) != 0) {
code = pdfi_create_Encoding(ctx, tmp, (pdf_obj *)fpriv.u.t1.Encoding, (pdf_obj **) & t1f->Encoding);
if (code >= 0)
code = 1;
@@ -685,15 +658,6 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pdfi_countdown(tmp);
tmp = NULL;
if (code == 1) {
- /* Since the underlying font stream can be shared between font descriptors,
- and the font descriptors can be shared between font objects, if we change
- the encoding, we can't share cached glyphs with other instances of this
- underlying font, so invalidate the UniqueID/XUID so the glyph cache won't
- try.
- */
- if (uid_is_XUID(&t1f->pfont->UID))
- uid_free(&t1f->pfont->UID, t1f->pfont->memory, "pdfi_read_type1_font");
- uid_set_invalid(&t1f->pfont->UID);
}
}
else {
@@ -706,6 +670,15 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->Encoding = fpriv.u.t1.Encoding;
pdfi_countup(t1f->Encoding);
}
+ /* Since the underlying font stream can be shared between font descriptors,
+ and the font descriptors can be shared between font objects, if we change
+ the encoding, we can't share cached glyphs with other instances of this
+ underlying font, so invalidate the UniqueID/XUID so the glyph cache won't
+ try.
+ */
+ if (uid_is_XUID(&t1f->pfont->UID))
+ uid_free(&t1f->pfont->UID, t1f->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&t1f->pfont->UID);
t1f->CharStrings = fpriv.u.t1.CharStrings;
pdfi_countup(t1f->CharStrings);
@@ -713,7 +686,11 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->Subrs = fpriv.u.t1.Subrs;
fpriv.u.t1.Subrs = NULL;
- t1f->NumSubrs = fpriv.u.t1.NumSubrs;
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, t1f->pfont);
+ if (code < 0) {
+ goto error;
+ }
t1f->blenddesignpositions = fpriv.u.t1.blenddesignpositions;
pdfi_countup(t1f->blenddesignpositions);
@@ -724,6 +701,18 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
t1f->blendaxistypes = fpriv.u.t1.blendaxistypes;
pdfi_countup(t1f->blendaxistypes);
+ key_known = false;
+ if (t1f->FontDescriptor != NULL) {
+ code = pdfi_dict_known(ctx, t1f->FontDescriptor, "FontFile", &key_known);
+ if (code < 0 || key_known == false) {
+ code = pdfi_dict_known(ctx, t1f->FontDescriptor, "FontFile2", &key_known);
+ if (code < 0 || key_known == false) {
+ code = pdfi_dict_known(ctx, t1f->FontDescriptor, "FontFile3", &key_known);
+ }
+ }
+ }
+ t1f->pfont->is_resource = (key_known == false);
+
code = gs_definefont(ctx->font_dir, (gs_font *) t1f->pfont);
if (code < 0) {
goto error;
@@ -753,20 +742,190 @@ pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dic
pdfi_countdown(fpriv.u.t1.blenddesignmap);
pdfi_countdown(fpriv.u.t1.blendfontbbox);
pdfi_countdown(fpriv.u.t1.blendaxistypes);
+ pdfi_countdown(fpriv.u.t1.Subrs);
if (fpriv.gsu.gst1.UID.xvalues != NULL) {
gs_free_object(ctx->memory, fpriv.gsu.gst1.UID.xvalues, "pdfi_read_type1_font(xuid)");
}
- if (fpriv.u.t1.Subrs) {
- int i;
- for (i = 0; i < fpriv.u.t1.NumSubrs; i++) {
- gs_free_object(ctx->memory, fpriv.u.t1.Subrs[i].data, "Subrs[i]");
+ if (code < 0) {
+ pdfi_countdown(t1f);
+ }
+ return code;
+}
+
+int
+pdfi_copy_type1_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont)
+{
+ int code = 0;
+ pdf_font_type1 *font = NULL;
+ gs_font_type1 *spfont1 = (gs_font_type1 *) spdffont->pfont;
+ gs_font_type1 *dpfont1;
+ gs_id t_id;
+ pdf_obj *tmp;
+
+ if (font_dict == NULL)
+ return_error(gs_error_invalidfont);
+
+ code = pdfi_alloc_t1_font(ctx, &font, font_dict->object_num);
+ if (code < 0)
+ return code;
+ dpfont1 = (gs_font_type1 *) font->pfont;
+
+ t_id = dpfont1->id;
+ memcpy(dpfont1, spfont1, sizeof(gs_font_type1));
+ dpfont1->id = t_id;
+ dpfont1->FAPI = NULL;
+ dpfont1->FAPI_font_data = NULL;
+
+ memcpy(font, spdffont, sizeof(pdf_font_type1));
+ font->pfont = (gs_font_base *)dpfont1;
+ font->refcnt = 1;
+ dpfont1->client_data = (void *)font;
+ font->filename = NULL;
+
+ dpfont1->notify_list.memory = NULL;
+ dpfont1->notify_list.first = NULL;
+ gs_notify_init(&dpfont1->notify_list, dpfont1->memory);
+
+ font->PDF_font = font_dict;
+ font->object_num = font_dict->object_num;
+ font->generation_num = font_dict->generation_num;
+ pdfi_countup(font->PDF_font);
+
+ /* We want basefont and descriptor, but we can live without them */
+ font->BaseFont = NULL;
+ code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &font->BaseFont);
+ if (code < 0) {
+ pdfi_countdown(font->BaseFont);
+ font->BaseFont = NULL;
+ }
+ font->FontDescriptor = NULL;
+ code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
+ if (code < 0) {
+ pdfi_countdown(font->FontDescriptor);
+ font->FontDescriptor = NULL;
+ }
+
+ pdfi_countup(font->Name);
+ pdfi_countup(font->CharStrings);
+ pdfi_countup(font->blenddesignpositions);
+ pdfi_countup(font->blenddesignmap);
+ pdfi_countup(font->blendfontbbox);
+ pdfi_countup(font->blendaxistypes);
+ pdfi_countup(font->Subrs);
+
+ if (font->BaseFont != NULL && ((pdf_name *)font->BaseFont)->length <= gs_font_name_max - 1) {
+ memcpy(dpfont1->key_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont1->key_name.size = ((pdf_name *)font->BaseFont)->length;
+ dpfont1->key_name.chars[dpfont1->key_name.size] = '\0';
+ memcpy(dpfont1->font_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont1->font_name.size = ((pdf_name *)font->BaseFont)->length;
+ dpfont1->font_name.chars[dpfont1->font_name.size] = '\0';
+ }
+
+ font->Encoding = NULL;
+ font->ToUnicode = NULL;
+ font->Widths = NULL;
+
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font *)font, (double)(0.001 / hypot(dpfont1->FontMatrix.xx, dpfont1->FontMatrix.xy)));
+
+ font->descflags = 0;
+ if (font->FontDescriptor != NULL) {
+ code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &font->descflags);
+ if (code >= 0) {
+ /* If both the symbolic and non-symbolic flag are set,
+ believe that latter.
+ */
+ if ((font->descflags & 32) != 0)
+ font->descflags = (font->descflags & ~4);
}
- gs_free_object(ctx->memory, fpriv.u.t1.Subrs, "Subrs");
}
+
+ if (pdfi_font_known_symbolic(font->BaseFont)) {
+ font->descflags |= 4;
+ }
+
+ tmp = NULL;
+ code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ if (code == 1) {
+ if ((pdfi_type_of(tmp) == PDF_NAME || pdfi_type_of(tmp) == PDF_DICT) && (font->descflags & 4) == 0) {
+ code = pdfi_create_Encoding(ctx, tmp, NULL, (pdf_obj **) & font->Encoding);
+ if (code >= 0)
+ code = 1;
+ }
+ else if (pdfi_type_of(tmp) == PDF_DICT && (font->descflags & 4) != 0) {
+ code = pdfi_create_Encoding(ctx, tmp, (pdf_obj *)spdffont->Encoding, (pdf_obj **) &font->Encoding);
+ if (code >= 0)
+ code = 1;
+ }
+ else
+ code = gs_error_undefined;
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ }
+ else {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+
+ if (code <= 0) {
+ font->Encoding = spdffont->Encoding;
+ pdfi_countup(font->Encoding);
+ }
+
+ /* Since various aspects of the font may differ (widths, encoding, etc)
+ we cannot reliably use the UniqueID/XUID for copied fonts.
+ */
+ if (uid_is_XUID(&font->pfont->UID))
+ uid_free(&font->pfont->UID, font->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&font->pfont->UID);
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, font->pfont);
if (code < 0) {
- pdfi_countdown(t1f);
+ goto error;
}
+
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tmp);
+ if (code >= 0 && pdfi_type_of(tmp) == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tmp, &tu);
+ pdfi_countdown(tmp);
+ tmp = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tmp != NULL && pdfi_type_of(tmp) != PDF_CMAP)) {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tmp = NULL;
+ }
+ font->ToUnicode = tmp;
+
+ code = gs_definefont(ctx->font_dir, (gs_font *) font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ code = pdfi_fapi_passfont((pdf_font *) font, 0, NULL, NULL, NULL, 0);
+ if (code < 0) {
+ goto error;
+ }
+ /* object_num can be zero if the dictionary was defined inline */
+ if (font->object_num != 0) {
+ (void)replace_cache_entry(ctx, (pdf_obj *) font);
+ }
+
+ *tpdffont = (pdf_font *)font;
+
+error:
+ if (code < 0)
+ pdfi_countdown(font);
+
return code;
}
@@ -774,7 +933,6 @@ int
pdfi_free_font_type1(pdf_obj *font)
{
pdf_font_type1 *t1f = (pdf_font_type1 *) font;
- int i;
gs_free_object(OBJ_MEMORY(font), t1f->pfont, "Free Type 1 gs_font");
@@ -789,20 +947,9 @@ pdfi_free_font_type1(pdf_obj *font)
pdfi_countdown(t1f->blenddesignmap);
pdfi_countdown(t1f->blendfontbbox);
pdfi_countdown(t1f->blendaxistypes);
+ pdfi_countdown(t1f->Subrs);
+ pdfi_countdown(t1f->filename);
- if (t1f->fake_glyph_names != NULL) {
- for (i = 0; i < t1f->LastChar; i++) {
- if (t1f->fake_glyph_names[i].data != NULL)
- gs_free_object(OBJ_MEMORY(font), t1f->fake_glyph_names[i].data, "Type 1 fake_glyph_name");
- }
- gs_free_object(OBJ_MEMORY(font), t1f->fake_glyph_names, "Type 1 fake_glyph_names");
- }
- if (t1f->NumSubrs > 0 && t1f->Subrs != NULL) {
- for (i = 0; i < t1f->NumSubrs; i++) {
- gs_free_object(OBJ_MEMORY(font), t1f->Subrs[i].data, "Type 1 Subr");
- }
- gs_free_object(OBJ_MEMORY(font), t1f->Subrs, "Type 1 Subrs");
- }
gs_free_object(OBJ_MEMORY(font), t1f->Widths, "Free Type 1 fontWidths");
gs_free_object(OBJ_MEMORY(font), t1f, "Free Type 1 font");
return 0;
diff --git a/pdf/pdf_font1.h b/pdf/pdf_font1.h
index 0385aafd..5fd41afa 100644
--- a/pdf/pdf_font1.h
+++ b/pdf/pdf_font1.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
@@ -21,6 +21,8 @@
int pdfi_read_type1_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *fbuf, int64_t fbuflen, pdf_font **ppdffont);
int pdfi_free_font_type1(pdf_obj *font);
+int pdfi_copy_type1_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont);
+
int pdfi_t1_global_glyph_code(const gs_font *pfont, gs_const_string *gstr, gs_glyph *pglyph);
#endif
diff --git a/pdf/pdf_font11.c b/pdf/pdf_font11.c
index 09712f60..d01e13e2 100644
--- a/pdf/pdf_font11.c
+++ b/pdf/pdf_font11.c
@@ -36,12 +36,12 @@ static int pdfi_cidtype2_string_proc(gs_font_type42 * pfont, ulong offset, uint
pdf_cidfont_type2 *ttfont = (pdf_cidfont_type2 *)pfont->client_data;
int code = 0;
- if (offset + length > ttfont->sfnt.size) {
+ if (offset + length > ttfont->sfnt->length) {
*pdata = NULL;
code = gs_note_error(gs_error_invalidfont);
}
else {
- *pdata = ttfont->sfnt.data + offset;
+ *pdata = ttfont->sfnt->data + offset;
}
return code;
}
@@ -51,8 +51,8 @@ static int pdfi_cidtype2_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph)
pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)pfont->client_data;
uint gid = glyph - GS_MIN_CID_GLYPH;
- if (pdffont11->cidtogidmap.size > (gid << 1) + 1) {
- gid = pdffont11->cidtogidmap.data[gid << 1] << 8 | pdffont11->cidtogidmap.data[(gid << 1) + 1];
+ if (pdffont11->cidtogidmap != NULL && pdffont11->cidtogidmap->length > (gid << 1) + 1) {
+ gid = pdffont11->cidtogidmap->data[gid << 1] << 8 | pdffont11->cidtogidmap->data[(gid << 1) + 1];
}
return (int)gid;
@@ -61,7 +61,7 @@ static int pdfi_cidtype2_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph)
static uint pdfi_cidtype2_get_glyph_index(gs_font_type42 *pfont, gs_glyph glyph)
{
pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)pfont->client_data;
- uint gid;
+ uint gid = 0;
if (glyph < GS_MIN_CID_GLYPH) {
gid = 0;
@@ -69,13 +69,10 @@ static uint pdfi_cidtype2_get_glyph_index(gs_font_type42 *pfont, gs_glyph glyph)
else {
if (glyph < GS_MIN_GLYPH_INDEX) {
gid = glyph - GS_MIN_CID_GLYPH;
- if (pdffont11->cidtogidmap.size > 0) {
- gid = pdffont11->cidtogidmap.data[gid << 1] << 8 | pdffont11->cidtogidmap.data[(gid << 1) + 1];
+ if (pdffont11->cidtogidmap != NULL && pdffont11->cidtogidmap->length > (gid << 1) + 1) {
+ gid = pdffont11->cidtogidmap->data[gid << 1] << 8 | pdffont11->cidtogidmap->data[(gid << 1) + 1];
}
}
- else {
- gid = (uint)(glyph - GS_MIN_GLYPH_INDEX);
- }
}
return gid;
@@ -151,15 +148,15 @@ pdfi_cidtype2_enumerate_glyph(gs_font *font, int *pindex,
if (*pindex <= 0)
*pindex = 0;
- if (pdffont11->cidtogidmap.size > 0) {
+ if (pdffont11->cidtogidmap != NULL && pdffont11->cidtogidmap->length > 0) {
do {
- *pglyph = pdffont11->cidtogidmap.data[(*pindex) << 1] << 8 | pdffont11->cidtogidmap.data[((*pindex) << 1) + 1];
+ *pglyph = pdffont11->cidtogidmap->data[(*pindex) << 1] << 8 | pdffont11->cidtogidmap->data[((*pindex) << 1) + 1];
(*pindex)++;
if (*pglyph == 0 && *pindex == 1) /* notdef - special case */
break;
- } while (*pglyph == 0 && ((*pindex) << 1) < pdffont11->cidtogidmap.size);
+ } while (*pglyph == 0 && ((*pindex) << 1) < pdffont11->cidtogidmap->length);
- if (((*pindex) << 1) >= pdffont11->cidtogidmap.size) {
+ if (((*pindex) << 1) >= pdffont11->cidtogidmap->length) {
*pindex = 0;
}
else {
@@ -312,9 +309,16 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
font->FontDescriptor = (pdf_dict *)fontdesc;
fontdesc = NULL;
- /* Ownership of buf is now part of the font and managed via its lifetime */
- font->sfnt.data = buf;
- font->sfnt.size = buflen;
+ code = pdfi_object_alloc(ctx, PDF_BUFFER, 0, (pdf_obj **)&font->sfnt);
+ if (code < 0) {
+ goto error;
+ }
+ pdfi_countup(font->sfnt);
+ code = pdfi_buffer_set_data((pdf_obj *)font->sfnt, buf, buflen);
+ if (code < 0) {
+ goto error;
+ }
+ buf = NULL;
/* Strictly speaking BaseFont is required, but we can continue without one */
code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, (pdf_obj **)&obj);
@@ -368,18 +372,26 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
code = pdfi_dict_knownget(ctx, font_dict, "CIDToGIDMap", (pdf_obj **)&obj);
if (code > 0) {
- font->cidtogidmap.data = NULL;
- font->cidtogidmap.size = 0;
/* CIDToGIDMap can only be a stream or a name, and if it's a name
it's only permitted to be "/Identity", so ignore it
*/
- if (obj->type == PDF_STREAM) {
+ if (pdfi_type_of(obj) == PDF_STREAM) {
+ byte *d;
int64_t sz;
- code = pdfi_stream_to_buffer(ctx, (pdf_stream *)obj, &(font->cidtogidmap.data), &sz);
+
+ code = pdfi_object_alloc(ctx, PDF_BUFFER, 0, (pdf_obj **)&font->cidtogidmap);
+ if (code < 0) {
+ goto error;
+ }
+ pdfi_countup(font->cidtogidmap);
+ code = pdfi_stream_to_buffer(ctx, (pdf_stream *)obj, &d, &sz);
+ if (code < 0) {
+ goto error;
+ }
+ code = pdfi_buffer_set_data((pdf_obj *)font->cidtogidmap, d, (int32_t)sz);
if (code < 0) {
goto error;
}
- font->cidtogidmap.size = (uint)sz;
}
pdfi_countdown(obj);
obj = NULL;
@@ -427,20 +439,31 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
pdfi_countdown(obj);
obj = NULL;
+
code = gs_type42_font_init((gs_font_type42 *)font->pfont, 0);
if (code < 0) {
goto error;
}
+ if (uid_is_XUID(&font->pfont->UID))
+ uid_free(&font->pfont->UID, font->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&font->pfont->UID);
+ font->pfont->id = gs_next_ids(ctx->memory, 1);
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, font->pfont);
+ if (code < 0)
+ goto error;
+
+
font->orig_glyph_info = font->pfont->procs.glyph_info;
font->pfont->procs.glyph_info = pdfi_cidtype2_glyph_info;
font->pfont->procs.enumerate_glyph = pdfi_cidtype2_enumerate_glyph;
- if (font->cidtogidmap.size > 0) {
+ if (font->cidtogidmap != NULL) {
gs_font_cid2 *cid2 = (gs_font_cid2 *)font->pfont;
- if (cid2->data.numGlyphs > font->cidtogidmap.size >> 1)
+ if (cid2->data.numGlyphs > font->cidtogidmap->length >> 1)
cid2->cidata.common.CIDCount = cid2->data.numGlyphs;
else {
- cid2->cidata.common.CIDCount = font->cidtogidmap.size >> 1;
+ cid2->cidata.common.CIDCount = font->cidtogidmap->length >> 1;
}
cid2->cidata.common.MaxCID = cid2->cidata.common.CIDCount;
}
@@ -453,16 +476,12 @@ int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
cid2->cidata.orig_procs.get_outline = cid2->data.get_outline;
cid2->data.get_glyph_index = pdfi_cidtype2_get_glyph_index;
- code = pdfi_font_generate_pseudo_XUID(ctx, font->PDF_font, font->pfont);
- if (code < 0)
- goto error;
-
code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont);
if (code < 0) {
goto error;
}
- code = pdfi_fapi_passfont((pdf_font *)font, 0, NULL, NULL, font->sfnt.data, font->sfnt.size);
+ code = pdfi_fapi_passfont((pdf_font *)font, 0, NULL, NULL, font->sfnt->data, font->sfnt->length);
if (code < 0) {
goto error;
}
@@ -487,9 +506,9 @@ int pdfi_free_font_cidtype2(pdf_obj *font)
gs_font_cid2 *pfont = (gs_font_cid2 *)pdfcidf->pfont;
gs_free_object(OBJ_MEMORY(pdfcidf), pfont, "pdfi_free_font_cidtype2(pfont)");
- gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf->cidtogidmap.data, "pdfi_free_font_cidtype2(cidtogidmap.data)");
- gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf->sfnt.data, "pdfi_free_font_cidtype2(sfnt.data)");
+ pdfi_countdown(pdfcidf->cidtogidmap);
+ pdfi_countdown(pdfcidf->sfnt);
pdfi_countdown(pdfcidf->PDF_font);
pdfi_countdown(pdfcidf->BaseFont);
pdfi_countdown(pdfcidf->FontDescriptor);
@@ -498,6 +517,7 @@ int pdfi_free_font_cidtype2(pdf_obj *font)
pdfi_countdown(pdfcidf->W2);
pdfi_countdown(pdfcidf->registry);
pdfi_countdown(pdfcidf->ordering);
+ pdfi_countdown(pdfcidf->filename);
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 f4788845..43ebced3 100644
--- a/pdf/pdf_font1C.c
+++ b/pdf/pdf_font1C.c
@@ -60,7 +60,7 @@ typedef struct pdfi_cff_font_priv_s {
pdf_array *W;
pdf_array *DW2;
pdf_array *W2;
- gs_string cidtogidmap;
+ pdf_buffer *cidtogidmap;
pdf_array *FDArray;
/* The registry and ordering strings in gs_font_cid0_data are just references to
strings assumed to be managed be managed by the interpreter - so we have to stash
@@ -145,6 +145,9 @@ pdfi_cff_glyph_data(gs_font_type1 *pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
}
if (code >= 0) {
code = pdfi_dict_get_by_key(ctx, cfffont->CharStrings, glyphname, (pdf_obj **) &charstring);
+ if (code < 0) {
+ code = pdfi_map_glyph_name_via_agl(cfffont->CharStrings, glyphname, &charstring);
+ }
if (code >= 0)
gs_glyph_data_from_bytes(pgd, charstring->data, 0, charstring->length, NULL);
}
@@ -205,11 +208,13 @@ pdfi_cff_seac_data(gs_font_type1 *pfont, int ccode, gs_glyph *pglyph, gs_const_s
pdfi_countup(glyphname);
code = pdfi_dict_get_by_key(ctx, cfffont->CharStrings, glyphname, (pdf_obj **)&charstring);
pdfi_countdown(glyphname);
- if (code >= 0)
- if (pgd != NULL)
+ if (code >= 0) {
+ if (pgd != NULL) {
gs_glyph_data_from_bytes(pgd, charstring->data, 0, charstring->length, NULL);
+ }
pdfi_countdown(charstring);
}
+ }
}
return code;
@@ -272,8 +277,13 @@ pdfi_cff_enumerate_glyph(gs_font *pfont, int *pindex,
else if (pdffont->pdfi_font_type != e_pdf_cidfont_type0 && pdffont->Encoding != NULL) {
unsigned int nindex;
code = (*ctx->get_glyph_index)(pfont, key->data, key->length, &nindex);
- if (code < 0)
- *pglyph = GS_NO_GLYPH;
+ if (code < 0) {
+ code = (*ctx->get_glyph_index)(pfont, (byte *)".notdef", 7, &nindex);
+ if (code < 0)
+ *pglyph = GS_NO_GLYPH;
+ else
+ *pglyph = (gs_glyph)nindex;
+ }
else
*pglyph = (gs_glyph)nindex;
}
@@ -296,9 +306,9 @@ pdfi_cff_enumerate_glyph(gs_font *pfont, int *pindex,
}
if (l > 0) {
pdf_cidfont_type0 *cffcidfont = (pdf_cidfont_type0 *) pdffont;
- if (cffcidfont->cidtogidmap.size > 0) {
- for (j = (cffcidfont->cidtogidmap.size >> 1) - 1; j >= 0; j--) {
- if (val == (cffcidfont->cidtogidmap.data[j << 1] << 8 | cffcidfont->cidtogidmap.data[(j << 1) + 1])) {
+ if (cffcidfont->cidtogidmap != NULL && cffcidfont->cidtogidmap->length > 0) {
+ for (j = (cffcidfont->cidtogidmap->length >> 1) - 1; j >= 0; j--) {
+ if (val == (cffcidfont->cidtogidmap->data[j << 1] << 8 | cffcidfont->cidtogidmap->data[(j << 1) + 1])) {
val = j;
break;
}
@@ -427,8 +437,8 @@ pdfi_cff_cid_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_glyph_data_t *p
else
gid = glyph - GS_MIN_CID_GLYPH;
- if (pdffont9->cidtogidmap.size > (gid << 1) + 1) {
- gid = pdffont9->cidtogidmap.data[gid << 1] << 8 | pdffont9->cidtogidmap.data[(gid << 1) + 1];
+ if (pdffont9->cidtogidmap != NULL && pdffont9->cidtogidmap->length > (gid << 1) + 1) {
+ gid = pdffont9->cidtogidmap->data[gid << 1] << 8 | pdffont9->cidtogidmap->data[(gid << 1) + 1];
}
l = gs_snprintf(nbuf, sizeof(nbuf), "%" PRId64, gid);
@@ -814,7 +824,8 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
n = 0;
while (p < e && code >= 0) {
- b0 = *p++;
+ b0 = *p;
+ p++;
switch (b0) {
case 22:
@@ -946,9 +957,10 @@ pdfi_read_cff_dict(byte *p, byte *e, pdfi_gs_cff_font_priv *ptpriv, cff_font_off
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;
+ int nlen = fnamestr->length > gs_font_name_max ? gs_font_name_max : fnamestr->length;
+ memcpy(ptpriv->font_name.chars, fnamestr->data, nlen);
+ memcpy(ptpriv->key_name.chars, fnamestr->data, nlen);
+ ptpriv->font_name.size = ptpriv->key_name.size = nlen;
pdfi_countdown(fnamestr);
}
break;
@@ -1698,7 +1710,6 @@ 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) {
@@ -1715,11 +1726,7 @@ 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);
+ code = pdfi_array_put(ctx, font->GlobalSubrs, (uint64_t) i, PDF_NULL_OBJ);
if (code < 0) {
pdfi_countdown(font->GlobalSubrs);
font->GlobalSubrs = NULL;
@@ -1736,7 +1743,6 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
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) {
@@ -1751,11 +1757,7 @@ 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);
+ code = pdfi_array_put(ctx, font->Subrs, (uint64_t) i, PDF_NULL_OBJ);
if (code < 0) {
pdfi_countdown(font->Subrs);
font->Subrs = NULL;
@@ -1838,7 +1840,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
pdf_font_cff *pdffont = NULL;
gs_font_type1 *pt1font;
- pdfi_init_cff_font_priv(ctx, &fdptpriv, font->cffdata, (font->cffend - font->cffdata) + 1, true);
+ pdfi_init_cff_font_priv(ctx, &fdptpriv, font->cffdata, (font->cffend - font->cffdata), true);
offsets.private_off = 0;
@@ -1879,9 +1881,8 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
/* Check the subrs index */
pdffont->Subrs = NULL;
- pdffont->subrs = fdptpriv.pdfcffpriv.subrs;
- if (pdffont->subrs) {
- p = pdfi_count_cff_index(pdffont->subrs, e, &pdffont->NumSubrs);
+ if (fdptpriv.pdfcffpriv.subrs) {
+ p = pdfi_count_cff_index(fdptpriv.pdfcffpriv.subrs, e, &pdffont->NumSubrs);
if (!p) {
pdffont->Subrs = NULL;
pdffont->NumSubrs = 0;
@@ -1897,7 +1898,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
for (j = 0; j < pdffont->NumSubrs; j++) {
pdf_string *subrstr;
- p = pdfi_find_cff_index(pdffont->subrs, e, j, &strp, &stre);
+ p = pdfi_find_cff_index(fdptpriv.pdfcffpriv.subrs, e, j, &strp, &stre);
if (p) {
code = pdfi_object_alloc(ctx, PDF_STRING, stre - strp, (pdf_obj **) &subrstr);
if (code >= 0) {
@@ -1975,7 +1976,7 @@ pdfi_read_cff(pdf_context *ctx, pdfi_gs_cff_font_priv *ptpriv)
if (g > maxcid) maxcid = g;
gs_snprintf(gkey, sizeof(gkey), "%d", g);
- code = pdfi_dict_put(ctx, font->CharStrings, gkey, (pdf_obj *) charstr);
+ code = pdfi_dict_put_unchecked(ctx, font->CharStrings, gkey, (pdf_obj *) charstr);
}
if (maxcid > ptpriv->pdfcffpriv.cidcount - 1)
ptpriv->pdfcffpriv.cidcount = maxcid + 1;
@@ -2270,8 +2271,13 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
fbuflen = tlen;
}
- code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
- if (code < 0) {
+ if (font_dict != NULL) {
+ code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
+ if (code < 0) {
+ fontdesc = NULL;
+ }
+ }
+ else {
fontdesc = NULL;
}
@@ -2335,7 +2341,7 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
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) {
+ if (code <= 0 || pdfi_type_of(suppl) != PDF_INT) {
cffcid->supplement = cffpriv.pdfcffpriv.supplement;
}
else {
@@ -2358,9 +2364,6 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->PDF_font = font_dict;
pdfi_countup(font_dict);
- cffcid->cidtogidmap.data = NULL;
- cffcid->cidtogidmap.size = 0;
-
pfont->client_data = cffcid;
cffcid->object_num = font_dict->object_num;
@@ -2384,23 +2387,35 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
pfont->cidata.common.CIDCount = cffpriv.pdfcffpriv.cidcount;
- cffcid->cidtogidmap.data = NULL;
- cffcid->cidtogidmap.size = 0;
+ cffcid->cidtogidmap = NULL;
code = pdfi_dict_knownget(ctx, font_dict, "CIDToGIDMap", (pdf_obj **) &obj);
if (code > 0) {
/* CIDToGIDMap can only be a stream or a name, and if it's a name
it's only permitted to be "/Identity", so ignore it
*/
- int64_t size = 0;
- if (obj->type == PDF_STREAM) {
- code = pdfi_stream_to_buffer(ctx, (pdf_stream *) obj, &(cffcid->cidtogidmap.data), &size);
+ if (pdfi_type_of(obj) == PDF_STREAM) {
+ byte *d;
+ int64_t sz;
+
+ code = pdfi_object_alloc(ctx, PDF_BUFFER, 0, (pdf_obj **)&cffcid->cidtogidmap);
+ if (code < 0) {
+ goto error;
+ }
+ pdfi_countup(cffcid->cidtogidmap);
+ code = pdfi_stream_to_buffer(ctx, (pdf_stream *)obj, &d, &sz);
+ if (code < 0) {
+ goto error;
+ }
+ code = pdfi_buffer_set_data((pdf_obj *)cffcid->cidtogidmap, d, (int32_t)sz);
+ if (code < 0) {
+ goto error;
+ }
}
pdfi_countdown(obj);
obj = NULL;
- cffcid->cidtogidmap.size = size;
- if (size > 0) {
- pfont->cidata.common.CIDCount = size >> 1;
+ if (cffcid->cidtogidmap != NULL && cffcid->cidtogidmap->length > 0) {
+ pfont->cidata.common.CIDCount = cffcid->cidtogidmap->length >> 1;
}
}
pfont->cidata.common.MaxCID = pfont->cidata.common.CIDCount - 1;
@@ -2438,10 +2453,10 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
else {
cffcid->W2 = NULL;
}
- code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, (gs_font_base *)cffcid->pfont);
- if (code < 0)
- uid_set_invalid(&cffcid->pfont->UID);
-
+ if (uid_is_XUID(&cffcid->pfont->UID))
+ uid_free(&cffcid->pfont->UID, cffcid->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&cffcid->pfont->UID);
+ cffcid->pfont->id = gs_next_ids(ctx->memory, 1);
}
else if (forcecid) {
pdf_obj *obj;
@@ -2581,22 +2596,34 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->PDF_font = font_dict;
pdfi_countup(font_dict);
- cffcid->cidtogidmap.data = NULL;
- cffcid->cidtogidmap.size = 0;
+ cffcid->cidtogidmap = NULL;
code = pdfi_dict_knownget(ctx, font_dict, "CIDToGIDMap", (pdf_obj **) &obj);
if (code > 0) {
+ byte *d;
+ int64_t sz;
/* CIDToGIDMap can only be a stream or a name, and if it's a name
it's only permitted to be "/Identity", so ignore it
*/
- int64_t size = 0;
- if (obj->type == PDF_STREAM) {
- code = pdfi_stream_to_buffer(ctx, (pdf_stream *) obj, &(cffcid->cidtogidmap.data), (int64_t *) &size);
+ if (pdfi_type_of(obj) == PDF_STREAM) {
+ code = pdfi_object_alloc(ctx, PDF_BUFFER, 0, (pdf_obj **)&cffcid->cidtogidmap);
+ if (code < 0) {
+ goto error;
+ }
+ pdfi_countup(cffcid->cidtogidmap);
+ code = pdfi_stream_to_buffer(ctx, (pdf_stream *)obj, &d, &sz);
+ if (code < 0) {
+ goto error;
+ }
+ code = pdfi_buffer_set_data((pdf_obj *)cffcid->cidtogidmap, d, (int32_t)sz);
+ if (code < 0) {
+ goto error;
+ }
}
pdfi_countdown(obj);
obj = NULL;
- cffcid->cidtogidmap.size = size;
- if (size > 0) {
- pfont->cidata.common.CIDCount = size >> 1;
+
+ if (cffcid->cidtogidmap != NULL && cffcid->cidtogidmap->length > 0) {
+ pfont->cidata.common.CIDCount = cffcid->cidtogidmap->length >> 1;
}
}
pfont->cidata.common.MaxCID = pfont->cidata.common.CIDCount - 1;
@@ -2635,17 +2662,17 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cffcid->W2 = NULL;
}
- code = pdfi_font_generate_pseudo_XUID(ctx, cffcid->PDF_font, ppdfont->pfont);
- if (code < 0)
- goto error;
-
+ if (uid_is_XUID(&cffcid->pfont->UID))
+ uid_free(&cffcid->pfont->UID, cffcid->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&cffcid->pfont->UID);
+ cffcid->pfont->id = gs_next_ids(ctx->memory, 1);
}
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);
+ code = pdfi_alloc_cff_font(ctx, &cfffont, font_dict != NULL ? font_dict->object_num : 0, false);
pfont = (gs_font_type1 *) cfffont->pfont;
ppdfont = (pdf_font *) cfffont;
@@ -2657,12 +2684,15 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
pfont->procs.glyph_info = pdfi_cff_glyph_info;
- cfffont->object_num = font_dict->object_num;
- cfffont->generation_num = font_dict->generation_num;
- cfffont->indirect_num = font_dict->indirect_num;
- cfffont->indirect_gen = font_dict->indirect_gen;
+ if (font_dict) {
+ cfffont->object_num = font_dict->object_num;
+ cfffont->generation_num = font_dict->generation_num;
+ 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);
+ }
- (void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &basefont);
cfffont->BaseFont = basefont;
cfffont->Name = basefont;
pdfi_countup(basefont);
@@ -2700,69 +2730,23 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cfffont->descflags |= 4;
}
- code = pdfi_dict_knownget_type(ctx, font_dict, "FirstChar", PDF_INT, &tmp);
- if (code == 1) {
- cfffont->FirstChar = ((pdf_num *) tmp)->value.i;
- pdfi_countdown(tmp);
- tmp = NULL;
- }
- else {
- cfffont->FirstChar = 0;
- }
- code = pdfi_dict_knownget_type(ctx, font_dict, "LastChar", PDF_INT, &tmp);
- if (code == 1) {
- cfffont->LastChar = ((pdf_num *) tmp)->value.i;
- pdfi_countdown(tmp);
- tmp = NULL;
- }
- else {
- cfffont->LastChar = 255;
- }
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)cfffont);
- cfffont->fake_glyph_names = (gs_string *) gs_alloc_bytes(ctx->memory, cfffont->LastChar * sizeof(gs_string), "pdfi_read_cff_font: fake_glyph_names");
- if (!cfffont->fake_glyph_names) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
- memset(cfffont->fake_glyph_names, 0x00, cfffont->LastChar * sizeof(gs_string));
- code = pdfi_dict_knownget_type(ctx, font_dict, "Widths", PDF_ARRAY, &tmp);
- if (code > 0) {
- int i;
- double x_scale;
- int num_chars = cfffont->LastChar - cfffont->FirstChar + 1;
-
- if (num_chars != pdfi_array_size((pdf_array *) tmp)) {
- pdfi_countdown(tmp);
- code = gs_note_error(gs_error_rangecheck);
- goto error;
- }
-
- cfffont->Widths = (double *)gs_alloc_bytes(ctx->memory, sizeof(double) * num_chars, "Type 1C font Widths array");
- if (cfffont->Widths == NULL) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
- memset(cfffont->Widths, 0x00, sizeof(double) * num_chars);
-
- /* Widths are defined assuming a 1000x1000 design grid, but we apply
- * them in font space - so undo the 1000x1000 scaling, and apply
- * the inverse of the font's x scaling
- */
- x_scale = 0.001 / hypot(pfont->FontMatrix.xx, pfont->FontMatrix.xy);
-
- for (i = 0; i < num_chars; i++) {
- code = pdfi_array_get_number(ctx, (pdf_array *) tmp, (uint64_t) i, &cfffont->Widths[i]);
- if (code < 0)
- goto error;
- cfffont->Widths[i] *= x_scale;
- }
+ /* Widths are defined assuming a 1000x1000 design grid, but we apply
+ * them in font space - so undo the 1000x1000 scaling, and apply
+ * the inverse of the font's x scaling
+ */
+ if (font_dict != NULL) {
+ /* ignore errors with widths... for now */
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)cfffont, (double)(0.001 / hypot(pfont->FontMatrix.xx, pfont->FontMatrix.xy)));
}
- pdfi_countdown(tmp);
- tmp = NULL;
- code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ if (font_dict != NULL)
+ code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ else
+ code = gs_error_undefined;
if (code == 1) {
- if ((cfffont->descflags & 4) != 0 && tmp->type == PDF_DICT) {
+ if ((cfffont->descflags & 4) != 0 && pdfi_type_of(tmp) == PDF_DICT) {
code = pdfi_create_Encoding(ctx, tmp, (pdf_obj *)cffpriv.pdfcffpriv.Encoding, (pdf_obj **) &cfffont->Encoding);
if (code >= 0) {
pdfi_countdown(cffpriv.pdfcffpriv.Encoding);
@@ -2770,7 +2754,7 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
code = 1;
}
}
- else if ((tmp->type == PDF_NAME || tmp->type == PDF_DICT)) {
+ else if ((pdfi_type_of(tmp) == PDF_NAME || pdfi_type_of(tmp) == PDF_DICT)) {
code = pdfi_create_Encoding(ctx, tmp, NULL, (pdf_obj **) &cfffont->Encoding);
if (code >= 0) {
pdfi_countdown(cffpriv.pdfcffpriv.Encoding);
@@ -2780,6 +2764,9 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
}
else
code = gs_error_undefined;
+
+ if (code == 1) {
+ }
pdfi_countdown(tmp);
tmp = NULL;
}
@@ -2792,15 +2779,27 @@ pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict,
cfffont->Encoding = cffpriv.pdfcffpriv.Encoding;
cffpriv.pdfcffpriv.Encoding = NULL;
}
- if (ctx->args.ignoretounicode != true) {
+
+ /* Since the underlying font stream can be shared between font descriptors,
+ and the font descriptors can be shared between font objects, if we change
+ the encoding, we can't share cached glyphs with other instances of this
+ underlying font, so invalidate the UniqueID/XUID so the glyph cache won't
+ try.
+ */
+ if (uid_is_XUID(&cfffont->pfont->UID))
+ uid_free(&cfffont->pfont->UID, cfffont->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&cfffont->pfont->UID);
+ cfffont->pfont->id = gs_next_ids(ctx->memory, 1);
+
+ if (ctx->args.ignoretounicode != true && font_dict != NULL) {
code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
+ if (code >= 0 && pdfi_type_of(tounicode) == 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)) {
+ if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
pdfi_countdown(tounicode);
tounicode = NULL;
code = 0;
@@ -2831,6 +2830,11 @@ error:
}
}
else {
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, ppdfont->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
code = gs_definefont(ctx->font_dir, (gs_font *) ppdfont->pfont);
if (code >= 0)
@@ -2840,6 +2844,7 @@ 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;
@@ -2898,6 +2903,168 @@ pdfi_read_type1C_font(pdf_context *ctx, pdf_dict *font_dict,
}
int
+pdfi_copy_cff_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont)
+{
+ int code = 0;
+ pdf_font_cff *font = NULL;
+ gs_font_type1 *spfont1 = (gs_font_type1 *) spdffont->pfont;
+ gs_font_type1 *dpfont1;
+ gs_id t_id;
+ pdf_obj *tmp;
+
+ if (font_dict == NULL)
+ return_error(gs_error_invalidfont);
+
+ code = pdfi_alloc_cff_font(ctx, &font, font_dict->object_num, false);
+ if (code < 0)
+ return code;
+ dpfont1 = (gs_font_type1 *) font->pfont;
+
+ t_id = dpfont1->id;
+ memcpy(dpfont1, spfont1, sizeof(gs_font_type1));
+ dpfont1->id = t_id;
+ dpfont1->FAPI = NULL;
+ dpfont1->FAPI_font_data = NULL;
+ dpfont1->notify_list.memory = NULL;
+ dpfont1->notify_list.first = NULL;
+ gs_notify_init(&dpfont1->notify_list, dpfont1->memory);
+
+ memcpy(font, spdffont, sizeof(pdf_font_type1));
+ font->refcnt = 1;
+ font->pfont = (gs_font_base *)dpfont1;
+ dpfont1->client_data = (void *)font;
+ font->filename = NULL;
+
+ font->PDF_font = font_dict;
+ font->object_num = font_dict->object_num;
+ font->generation_num = font_dict->generation_num;
+ pdfi_countup(font->PDF_font);
+
+ /* We want basefont and descriptor, but we can live without them */
+ font->BaseFont = NULL;
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &font->BaseFont);
+ font->FontDescriptor = NULL;
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
+
+ pdfi_countup(font->Name);
+ pdfi_countup(font->CharStrings);
+ pdfi_countup(font->Subrs);
+ pdfi_countup(font->GlobalSubrs);
+
+ if (font->BaseFont != NULL && ((pdf_name *)font->BaseFont)->length <= gs_font_name_max) {
+ memcpy(dpfont1->key_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont1->key_name.size = ((pdf_name *)font->BaseFont)->length;
+ memcpy(dpfont1->font_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont1->font_name.size = ((pdf_name *)font->BaseFont)->length;
+ }
+
+ font->Encoding = NULL;
+ font->ToUnicode = NULL;
+ font->Widths = NULL;
+
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font *)font, (double)(0.001 / hypot(dpfont1->FontMatrix.xx, dpfont1->FontMatrix.xy)));
+
+ font->descflags = 0;
+ if (font->FontDescriptor != NULL) {
+ code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &font->descflags);
+ if (code >= 0) {
+ /* If both the symbolic and non-symbolic flag are set,
+ believe that latter.
+ */
+ if ((font->descflags & 32) != 0)
+ font->descflags = (font->descflags & ~4);
+ }
+ }
+
+ if (pdfi_font_known_symbolic(font->BaseFont)) {
+ font->descflags |= 4;
+ }
+
+
+ tmp = NULL;
+ code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ if (code == 1) {
+ if ((pdfi_type_of(tmp) == PDF_NAME || pdfi_type_of(tmp) == PDF_DICT) && (font->descflags & 4) == 0) {
+ code = pdfi_create_Encoding(ctx, tmp, NULL, (pdf_obj **) & font->Encoding);
+ if (code >= 0)
+ code = 1;
+ }
+ else if (pdfi_type_of(tmp) == PDF_DICT && (font->descflags & 4) != 0) {
+ code = pdfi_create_Encoding(ctx, tmp, (pdf_obj *)spdffont->Encoding, (pdf_obj **) &font->Encoding);
+ if (code >= 0)
+ code = 1;
+ }
+ else
+ code = gs_error_undefined;
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ }
+ else {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+
+ if (code <= 0) {
+ font->Encoding = spdffont->Encoding;
+ pdfi_countup(font->Encoding);
+ }
+
+ /* Since various aspects of the font may differ (widths, encoding, etc)
+ we cannot reliably use the UniqueID/XUID for copied fonts.
+ */
+ if (uid_is_XUID(&font->pfont->UID))
+ uid_free(&font->pfont->UID, font->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&font->pfont->UID);
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tmp);
+ if (code >= 0 && pdfi_type_of(tmp) == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tmp, &tu);
+ pdfi_countdown(tmp);
+ tmp = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tmp != NULL && pdfi_type_of(tmp) != PDF_CMAP)) {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tmp = NULL;
+ }
+ font->ToUnicode = tmp;
+
+ code = gs_definefont(ctx->font_dir, (gs_font *) font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ code = pdfi_fapi_passfont((pdf_font *) font, 0, NULL, NULL, NULL, 0);
+ if (code < 0) {
+ goto error;
+ }
+ /* object_num can be zero if the dictionary was defined inline */
+ if (font->object_num != 0) {
+ (void)replace_cache_entry(ctx, (pdf_obj *) font);
+ }
+
+ *tpdffont = (pdf_font *)font;
+
+error:
+ if (code < 0)
+ pdfi_countdown(font);
+ return code;
+}
+
+int
pdfi_free_font_cff(pdf_obj *font)
{
pdf_font_cff *pdfontcff = (pdf_font_cff *) font;
@@ -2913,8 +3080,8 @@ pdfi_free_font_cff(pdf_obj *font)
pdfi_countdown(pdfontcff->GlobalSubrs);
pdfi_countdown(pdfontcff->Encoding);
pdfi_countdown(pdfontcff->ToUnicode);
+ pdfi_countdown(pdfontcff->filename);
- gs_free_object(OBJ_MEMORY(font), pdfontcff->fake_glyph_names, "Type 2 fake_glyph_names");
gs_free_object(OBJ_MEMORY(font), pdfontcff->Widths, "Type 2 fontWidths");
gs_free_object(OBJ_MEMORY(font), pdfontcff, "pdfi_free_font_cff(pbfont)");
@@ -2948,8 +3115,9 @@ pdfi_free_font_cidtype0(pdf_obj *font)
pdfi_countdown(pdfont0->FDArray);
pdfi_countdown(pdfont0->registry);
pdfi_countdown(pdfont0->ordering);
+ pdfi_countdown(pdfont0->cidtogidmap);
+ pdfi_countdown(pdfont0->filename);
- gs_free_object(OBJ_MEMORY(font), pdfont0->cidtogidmap.data, "pdfi_free_font_cff(cidtogidmap.data)");
gs_free_object(OBJ_MEMORY(font), pdfont0, "pdfi_free_font_cff(pbfont)");
return 0;
diff --git a/pdf/pdf_font1C.h b/pdf/pdf_font1C.h
index e02b6342..ea8c7084 100644
--- a/pdf/pdf_font1C.h
+++ b/pdf/pdf_font1C.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
@@ -19,10 +19,11 @@
#define PDF_TYPE1C_FONT
int pdfi_read_type1C_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont);
int pdfi_cff_global_glyph_code(const gs_font *pfont, gs_const_string *gstr, gs_glyph *pglyph);
-int pdfi_free_font_cff(pdf_obj *font);
int pdfi_read_cff_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *pfbuf, int64_t fbuflen, bool forcecid, pdf_font **ppdffont);
+int pdfi_copy_cff_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont);
+int pdfi_free_font_cff(pdf_obj *font);
int pdfi_free_font_cidtype0(pdf_obj *font);
#endif
diff --git a/pdf/pdf_font3.c b/pdf/pdf_font3.c
index 7ecd3bff..708e7658 100644
--- a/pdf/pdf_font3.c
+++ b/pdf/pdf_font3.c
@@ -74,7 +74,7 @@ pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
}
if (code < 0)
goto build_char_error;
- if (CharProc->type != PDF_STREAM) {
+ if (pdfi_type_of(CharProc) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto build_char_error;
}
@@ -223,6 +223,8 @@ int pdfi_free_font_type3(pdf_obj *font)
pdfi_countdown(t3font->CharProcs);
pdfi_countdown(t3font->Encoding);
pdfi_countdown(t3font->ToUnicode);
+ pdfi_countdown(t3font->filename); /* Should never exist, but just in case */
+
gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font");
return 0;
}
@@ -230,10 +232,9 @@ int pdfi_free_font_type3(pdf_obj *font)
int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont)
{
- int code = 0, i, num_chars = 0;
+ int code = 0;
pdf_font_type3 *font = NULL;
pdf_obj *obj = NULL;
- double f;
pdf_obj *tounicode = NULL;
*ppdffont = NULL;
@@ -271,44 +272,15 @@ int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
if (code < 0)
goto font3_error;
- code = pdfi_dict_get_number(ctx, font_dict, "FirstChar", &f);
- if (code < 0)
- goto font3_error;
- font->FirstChar = (int)f;
-
- code = pdfi_dict_get_number(ctx, font_dict, "LastChar", &f);
- if (code < 0)
- goto font3_error;
- font->LastChar = (int)f;
- num_chars = (font->LastChar - font->FirstChar) + 1;
code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
if (code < 0)
goto font3_error;
- code = pdfi_dict_knownget_type(ctx, font_dict, "Widths", PDF_ARRAY, (pdf_obj **)&obj);
- if (code < 0)
- goto font3_error;
- if (code > 0) {
- if (num_chars != pdfi_array_size((pdf_array *)obj)) {
- code = gs_note_error(gs_error_rangecheck);
- goto font3_error;
- }
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
+ /* ignore errors with widths... for now */
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 1.0);
- font->Widths = (double *)gs_alloc_bytes(ctx->memory, sizeof(double) * num_chars, "type 3 font Widths array");
- if (font->Widths == NULL) {
- code = gs_note_error(gs_error_VMerror);
- goto font3_error;
- }
- memset(font->Widths, 0x00, sizeof(double) * num_chars);
- for (i = 0; i < num_chars; i++) {
- code = pdfi_array_get_number(ctx, (pdf_array *)obj, (uint64_t)i, &font->Widths[i]);
- if (code < 0)
- goto font3_error;
- }
- }
- pdfi_countdown(obj);
- obj = NULL;
code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj);
if (code < 0)
@@ -324,13 +296,13 @@ int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream
if (ctx->args.ignoretounicode != true) {
code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
+ if (code >= 0 && pdfi_type_of(tounicode) == 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)) {
+ if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
pdfi_countdown(tounicode);
tounicode = NULL;
code = 0;
diff --git a/pdf/pdf_fontTT.c b/pdf/pdf_fontTT.c
index aec3ee7b..d7d43e62 100644
--- a/pdf/pdf_fontTT.c
+++ b/pdf/pdf_fontTT.c
@@ -44,12 +44,12 @@ pdfi_ttf_string_proc(gs_font_type42 * pfont, ulong offset, uint length, const by
pdf_font_truetype *ttfont = (pdf_font_truetype *)pfont->client_data;
int code = 0;
- if ((uint64_t)offset + length > ttfont->sfnt.size) {
+ if ((uint64_t)offset + length > ttfont->sfnt->length) {
*pdata = NULL;
code = gs_note_error(gs_error_invalidfont);
}
else {
- *pdata = ttfont->sfnt.data + offset;
+ *pdata = ttfont->sfnt->data + offset;
}
return code;
}
@@ -356,11 +356,10 @@ static int pdfi_set_type42_data_procs(gs_font_type42 *pfont)
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;
+ int code = 0, i;
pdf_obj *fontdesc = NULL;
pdf_obj *obj = NULL;
pdf_obj *basefont = NULL;
- double f;
int64_t descflags;
bool encoding_known = false;
bool forced_symbolic = false;
@@ -371,96 +370,71 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
*ppdffont = NULL;
- code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
- if (code <= 0) {
- code = gs_note_error(gs_error_invalidfont);
- goto error;
- }
+ if (font_dict != NULL)
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc);
if ((code = pdfi_alloc_tt_font(ctx, &font, false)) < 0) {
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;
+ if (font_dict != NULL) {
+ 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;
- code = pdfi_dict_get_number(ctx, font_dict, "FirstChar", &f);
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
+
+ code = pdfi_object_alloc(ctx, PDF_BUFFER, 0, (pdf_obj **)&font->sfnt);
if (code < 0) {
goto error;
}
- font->FirstChar = (int)f;
-
- code = pdfi_dict_get_number(ctx, font_dict, "LastChar", &f);
+ pdfi_countup(font->sfnt);
+ code = pdfi_buffer_set_data((pdf_obj *)font->sfnt, buf, buflen);
if (code < 0) {
goto error;
}
- font->LastChar = (int)f;
-
- num_chars = font->LastChar - font->FirstChar + 1;
-
- font->sfnt.data = buf;
- font->sfnt.size = buflen;
buf = NULL;
/* Strictly speaking BaseFont is required, but we can continue without one */
- code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, (pdf_obj **)&basefont);
- if (code > 0) {
- pdf_name *nobj = (pdf_name *)basefont;
- int nlen = nobj->length > gs_font_name_max ? gs_font_name_max : nobj->length;
-
- memcpy(font->pfont->key_name.chars, nobj->data, nlen);
- font->pfont->key_name.chars[nlen] = 0;
- font->pfont->key_name.size = nlen;
- memcpy(font->pfont->font_name.chars, nobj->data, nlen);
- font->pfont->font_name.chars[nlen] = 0;
- font->pfont->font_name.size = nlen;
- pdfi_countdown(obj);
- obj = NULL;
+ if (font_dict != NULL) {
+ code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, (pdf_obj **)&basefont);
+ if (code > 0) {
+ pdf_name *nobj = (pdf_name *)basefont;
+ int nlen = nobj->length > gs_font_name_max ? gs_font_name_max : nobj->length;
+
+ memcpy(font->pfont->key_name.chars, nobj->data, nlen);
+ font->pfont->key_name.chars[nlen] = 0;
+ font->pfont->key_name.size = nlen;
+ memcpy(font->pfont->font_name.chars, nobj->data, nlen);
+ font->pfont->font_name.chars[nlen] = 0;
+ font->pfont->font_name.size = nlen;
+ pdfi_countdown(obj);
+ obj = NULL;
+ }
}
font->BaseFont = basefont;
basefont = NULL;
font->PDF_font = font_dict;
pdfi_countup(font_dict);
- code = pdfi_dict_knownget_type(ctx, font_dict, "Widths", PDF_ARRAY, (pdf_obj **)&obj);
- if (code < 0)
- goto error;
- if (code > 0) {
- if (num_chars != pdfi_array_size((pdf_array *)obj)) {
- code = gs_note_error(gs_error_rangecheck);
- goto error;
- }
-
- font->Widths = (double *)gs_alloc_bytes(ctx->memory, sizeof(double) * num_chars, "truetype font Widths array");
- if (font->Widths == NULL) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
- memset(font->Widths, 0x00, sizeof(double) * num_chars);
- for (i = 0; i < num_chars; i++) {
- code = pdfi_array_get_number(ctx, (pdf_array *)obj, (uint64_t)i, &font->Widths[i]);
- if (code < 0)
- goto error;
- font->Widths[i] /= 1000;
- }
- }
- pdfi_countdown(obj);
- obj = NULL;
+ /* ignore errors with widths... for now */
+ if (font_dict != NULL)
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 0.001);
- if (ctx->args.ignoretounicode != true) {
+ if (ctx->args.ignoretounicode != true && font_dict != NULL) {
code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
- if (code >= 0 && tounicode->type == PDF_STREAM) {
+ if (code >= 0 && pdfi_type_of(tounicode) == 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)) {
+ if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
pdfi_countdown(tounicode);
tounicode = NULL;
code = 0;
@@ -472,11 +446,20 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
font->ToUnicode = tounicode;
tounicode = NULL;
- code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &descflags);
- if (code < 0)
+ if (font->FontDescriptor != NULL) {
+ code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &descflags);
+ if (code < 0)
+ descflags = 0;
+ }
+ else {
descflags = 0;
+ }
+
+ if (font_dict != NULL)
+ code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj);
+ else
+ code = gs_error_undefined;
- code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj);
if (code < 0) {
static const char encstr[] = "WinAnsiEncoding";
code = pdfi_name_alloc(ctx, (byte *)encstr, strlen(encstr), (pdf_obj **)&obj);
@@ -508,13 +491,6 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
pdfi_countdown(obj);
obj = NULL;
- font->fake_glyph_names = (gs_string *)gs_alloc_bytes(OBJ_MEMORY(font), font->LastChar * sizeof(gs_string), "pdfi_read_truetype_font: fake_glyph_names");
- if (!font->fake_glyph_names) {
- code = gs_note_error(gs_error_VMerror);
- goto error;
- }
- memset(font->fake_glyph_names, 0x00, font->LastChar * sizeof(gs_string));
-
code = gs_type42_font_init((gs_font_type42 *)font->pfont, 0);
if (code < 0) {
goto error;
@@ -565,7 +541,9 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
font->descflags = descflags;
}
else if (encoding_known == true) {
- static const char encstr[] = "WinAnsiEncoding";
+ static const char mrencstr[] = "MacRomanEncoding";
+ static const char waencstr[] = "WinAnsiEncoding";
+ const char *encstr = ((cmaps_available & CMAP_TABLE_31_PRESENT) == CMAP_TABLE_31_PRESENT) ? waencstr : mrencstr;
font->descflags = descflags & ~4;
code = pdfi_name_alloc(ctx, (byte *)encstr, strlen(encstr), (pdf_obj **)&obj);
if (code >= 0)
@@ -586,12 +564,30 @@ int pdfi_read_truetype_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *str
font->descflags = descflags;
}
+ if (uid_is_XUID(&font->pfont->UID))
+ uid_free(&font->pfont->UID, font->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&font->pfont->UID);
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ if ((font->descflags & 4) == 0) {
+ /* Horrid hacky solution */
+ /* We don't want to draw the TTF notdef */
+ gs_font_type42 *gst42 = ((gs_font_type42 *)font->pfont);
+ if (gst42->data.len_glyphs != NULL && gst42->data.len_glyphs[0] > 10) {
+ gst42->data.len_glyphs[0] = 0;
+ }
+ }
+
code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont);
if (code < 0) {
goto error;
}
- code = pdfi_fapi_passfont((pdf_font *)font, 0, NULL, NULL, font->sfnt.data, font->sfnt.size);
+ code = pdfi_fapi_passfont((pdf_font *)font, 0, NULL, NULL, font->sfnt->data, font->sfnt->length);
if (code < 0) {
goto error;
}
@@ -613,30 +609,175 @@ error:
return code;
}
+int
+pdfi_copy_truetype_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont)
+{
+ int code = 0;
+ pdf_font_truetype *font = NULL;
+ gs_font_type42 *spfont1 = (gs_font_type42 *) spdffont->pfont;
+ gs_font_type42 *dpfont42;
+ gs_id t_id;
+ pdf_obj *tmp;
+
+ if (font_dict == NULL)
+ return_error(gs_error_invalidfont);
+
+ code = pdfi_alloc_tt_font(ctx, &font, font_dict->object_num);
+ if (code < 0)
+ return code;
+ dpfont42 = (gs_font_type42 *) font->pfont;
+
+ t_id = dpfont42->id;
+ memcpy(dpfont42, spfont1, sizeof(gs_font_type42));
+ dpfont42->id = t_id;
+ dpfont42->FAPI = NULL;
+ dpfont42->FAPI_font_data = NULL;
+ dpfont42->notify_list.memory = NULL;
+ dpfont42->notify_list.first = NULL;
+ gs_notify_init(&dpfont42->notify_list, dpfont42->memory);
+
+ memcpy(font, spdffont, sizeof(pdf_font_truetype));
+ font->refcnt = 1;
+ font->filename = NULL;
+
+ font->pfont = (gs_font_base *)dpfont42;
+ dpfont42->client_data = (void *)font;
+
+ font->PDF_font = font_dict;
+ font->object_num = font_dict->object_num;
+ font->generation_num = font_dict->generation_num;
+ pdfi_countup(font->PDF_font);
+
+ /* We want basefont and descriptor, but we can live without them */
+ font->BaseFont = NULL;
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, &font->BaseFont);
+ font->FontDescriptor = NULL;
+ (void)pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
+
+ pdfi_countup(font->sfnt);
+
+ if (font->BaseFont != NULL && ((pdf_name *)font->BaseFont)->length <= gs_font_name_max) {
+ memcpy(dpfont42->key_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont42->key_name.size = ((pdf_name *)font->BaseFont)->length;
+ memcpy(dpfont42->font_name.chars, ((pdf_name *)font->BaseFont)->data, ((pdf_name *)font->BaseFont)->length);
+ dpfont42->font_name.size = ((pdf_name *)font->BaseFont)->length;
+ }
+
+ font->Encoding = NULL;
+ font->ToUnicode = NULL;
+ font->Widths = NULL;
+
+ pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
+ (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, (double)0.001);
+
+ font->descflags = 0;
+ if (font->FontDescriptor != NULL) {
+ code = pdfi_dict_get_int(ctx, font->FontDescriptor, "Flags", &font->descflags);
+ if (code >= 0) {
+ /* If both the symbolic and non-symbolic flag are set,
+ believe that latter.
+ */
+ if ((font->descflags & 32) != 0)
+ font->descflags = (font->descflags & ~4);
+ }
+ }
+
+ tmp = NULL;
+ code = pdfi_dict_knownget(ctx, font_dict, "Encoding", &tmp);
+ if (code == 1) {
+ if ((pdfi_type_of(tmp) == PDF_NAME || pdfi_type_of(tmp) == PDF_DICT) && (font->descflags & 4) == 0) {
+ code = pdfi_create_Encoding(ctx, tmp, NULL, (pdf_obj **) & font->Encoding);
+ }
+ else if (pdfi_type_of(tmp) == PDF_DICT && (font->descflags & 4) != 0) {
+ code = pdfi_create_Encoding(ctx, tmp, (pdf_obj *)spdffont->Encoding, (pdf_obj **) &font->Encoding);
+ }
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ }
+ else {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+ if (code < 0) {
+ goto error;
+ }
+
+ /* Since various aspects of the font may differ (widths, encoding, etc)
+ we cannot reliably use the UniqueID/XUID for copied fonts.
+ */
+ if (uid_is_XUID(&font->pfont->UID))
+ uid_free(&font->pfont->UID, font->pfont->memory, "pdfi_read_type1_font");
+ uid_set_invalid(&font->pfont->UID);
+
+ code = pdfi_font_generate_pseudo_XUID(ctx, font_dict, font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ if (code <= 0) {
+ font->Encoding = spdffont->Encoding;
+ pdfi_countup(font->Encoding);
+ }
+
+ if (ctx->args.ignoretounicode != true) {
+ code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tmp);
+ if (code >= 0 && pdfi_type_of(tmp) == PDF_STREAM) {
+ pdf_cmap *tu = NULL;
+ code = pdfi_read_cmap(ctx, tmp, &tu);
+ pdfi_countdown(tmp);
+ tmp = (pdf_obj *)tu;
+ }
+ if (code < 0 || (tmp != NULL && pdfi_type_of(tmp) != PDF_CMAP)) {
+ pdfi_countdown(tmp);
+ tmp = NULL;
+ code = 0;
+ }
+ }
+ else {
+ tmp = NULL;
+ }
+ font->ToUnicode = tmp;
+ code = gs_definefont(ctx->font_dir, (gs_font *) font->pfont);
+ if (code < 0) {
+ goto error;
+ }
+
+ code = pdfi_fapi_passfont((pdf_font *) font, 0, NULL, NULL, NULL, 0);
+ if (code < 0) {
+ goto error;
+ }
+ /* object_num can be zero if the dictionary was defined inline */
+ if (font->object_num != 0) {
+ (void)replace_cache_entry(ctx, (pdf_obj *) font);
+ }
+
+ *tpdffont = (pdf_font *)font;
+
+error:
+ if (code < 0)
+ pdfi_countdown(font);
+ return code;
+}
+
int pdfi_free_font_truetype(pdf_obj *font)
{
pdf_font_truetype *ttfont = (pdf_font_truetype *)font;
- int i;
+
if (ttfont->pfont)
gs_free_object(OBJ_MEMORY(ttfont), ttfont->pfont, "Free TrueType gs_font");
if (ttfont->Widths)
gs_free_object(OBJ_MEMORY(ttfont), ttfont->Widths, "Free TrueType font Widths array");
- if (ttfont->fake_glyph_names != NULL) {
- for (i = 0; i < ttfont->LastChar; i++) {
- if (ttfont->fake_glyph_names[i].data != NULL)
- gs_free_object(OBJ_MEMORY(ttfont), ttfont->fake_glyph_names[i].data, "Free TrueType fake_glyph_name");
- }
- }
- gs_free_object(OBJ_MEMORY(ttfont), ttfont->fake_glyph_names, "Free TrueType fake_glyph_names");
- gs_free_object(OBJ_MEMORY(ttfont), ttfont->sfnt.data, "Free TrueType font sfnt buffer");
-
+ pdfi_countdown(ttfont->sfnt);
pdfi_countdown(ttfont->FontDescriptor);
pdfi_countdown(ttfont->Encoding);
pdfi_countdown(ttfont->BaseFont);
pdfi_countdown(ttfont->PDF_font);
pdfi_countdown(ttfont->ToUnicode);
+ pdfi_countdown(ttfont->filename);
+
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 90e4086e..14932f66 100644
--- a/pdf/pdf_fontTT.h
+++ b/pdf/pdf_fontTT.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
@@ -19,6 +19,7 @@
#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, int findex, pdf_font **ppdffont);
+int pdfi_copy_truetype_font(pdf_context *ctx, pdf_font *spdffont, pdf_dict *font_dict, pdf_font **tpdffont);
int pdfi_free_font_truetype(pdf_obj *font);
#endif
diff --git a/pdf/pdf_font_types.h b/pdf/pdf_font_types.h
index f83a0851..f29088f5 100644
--- a/pdf/pdf_font_types.h
+++ b/pdf/pdf_font_types.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
@@ -84,18 +84,18 @@ typedef enum pdf_font_type_e {
pdf_dict *PDF_font; /* The original font dictionary from the PDF file */\
pdf_obj *BaseFont; /* Should be a name object, but best allow for strings as well */\
pdf_dict *FontDescriptor; /* For PDF up to 1.4 this may be absent for the base 14 */ \
- int64_t descflags
-
+ int64_t descflags; \
+ pdf_obj *ToUnicode; /* Name or stream (technically should be a stream, but we've seen Identity names */ \
+ pdf_string *filename /* If we read this from disk, this is the file it came from */
#define pdf_font_common \
pdf_font_base;\
pdf_obj *Name; /* Should be a name object, but best allow for strings as well */\
unsigned int FirstChar; /* For PDF up to 1.4 this may be absent for the base 14 */\
unsigned int LastChar; /* For PDF up to 1.4 this may be absent for the base 14 */\
- double *Widths; /* For PDF up to 1.4 this may be absent for the base 14 */\
- pdf_array *Encoding; /* Array built from name or dictionary */\
- pdf_obj *ToUnicode; /* Name or stream (technically should be a stream, but we've seen Identity names */ \
- gs_string *fake_glyph_names /* For when we encounter a glyph not in the Encoding */
+ double MissingWidth; \
+ double *Widths; /* For PDF up to 1.4 this may be absent for the base 14 */\
+ pdf_array *Encoding /* Array built from name or dictionary */\
/* The registry and ordering strings in gs_font_cid0_data are just references to
@@ -112,7 +112,7 @@ typedef enum pdf_font_type_e {
pdf_string *registry; \
pdf_string *ordering; \
int supplement; \
- gs_string cidtogidmap; \
+ pdf_buffer *cidtogidmap; \
bool substitute; /* We need to know what a CIDFont is a substitute */ \
font_proc_glyph_info((*orig_glyph_info))
@@ -147,16 +147,14 @@ typedef struct pdf_font_type0_s {
pdf_obj *Encoding; /* CMap */
pdf_array *DescendantFonts; /* A single element array specifying the CIDFont dictionary */
- pdf_obj *ToUnicode; /* Name or stream (technically shoudl be a stream, but we've seen Identity names */
pdfi_cid_decoding_t *decoding; /* Used when substituting a non-Identity CIDFont */
pdfi_cid_subst_nwp_table_t *substnwp; /* Also used for CIDFont substitions */
} pdf_font_type0;
typedef struct pdf_font_type1_s {
pdf_font_common;
- gs_string *Subrs;
+ pdf_array *Subrs;
pdf_dict *CharStrings;
- int NumSubrs;
/* Multiple Master Support - weightvector is stored in gs_font_type1 */
pdf_array *blenddesignpositions;
pdf_array *blenddesignmap;
@@ -171,11 +169,6 @@ typedef struct pdf_font_cff_s {
pdf_array *GlobalSubrs;
int NumGlobalSubrs;
pdf_dict *CharStrings;
- byte *cffdata;
- byte *cffend;
- byte *gsubrs;
- byte *subrs;
- byte *charstrings;
int ncharstrings;
} pdf_font_cff;
@@ -197,7 +190,7 @@ typedef enum {
typedef struct pdf_font_truetype_s {
pdf_font_common;
- gs_string sfnt;
+ pdf_buffer *sfnt;
pdfi_truetype_cmap cmap;
} pdf_font_truetype;
@@ -212,11 +205,6 @@ typedef struct pdf_cidfont_type0_s {
pdf_array *GlobalSubrs;
int NumGlobalSubrs;
pdf_dict *CharStrings;
- byte *cffdata;
- byte *cffend;
- byte *gsubrs;
- byte *subrs;
- byte *charstrings;
int ncharstrings;
pdf_array *FDArray;
int cidcount;
@@ -225,7 +213,7 @@ typedef struct pdf_cidfont_type0_s {
typedef struct pdf_cidfont_type2_s {
pdf_cid_font_common;
- gs_string sfnt;
+ pdf_buffer *sfnt;
} pdf_cidfont_type2;
#endif
diff --git a/pdf/pdf_fontps.c b/pdf/pdf_fontps.c
index 3ab399b9..5cfa1652 100644
--- a/pdf/pdf_fontps.c
+++ b/pdf/pdf_fontps.c
@@ -885,7 +885,7 @@ ps_font_def_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
}
}
if (code >= 0) {
- pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignpositions, i, (pdf_obj *)sa);
+ code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.blenddesignpositions, i, (pdf_obj *)sa);
}
pdfi_countdown(sa);
}
@@ -1045,21 +1045,14 @@ ps_font_array_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
!memcmp(s->cur[-1].val.name, PDF_PS_OPER_NAME_AND_LEN("Subrs"))) {
if (s->cur[0].val.i > 0) {
- if (priv->u.t1.Subrs != NULL) {
- int i;
- for (i = 0; i < priv->u.t1.NumSubrs; i++) {
- gs_free_object(mem, priv->u.t1.Subrs[i].data, "ps_font_array_func(Subrs[i])");
- }
- gs_free_object(mem, priv->u.t1.Subrs, "ps_font_array_func(Subrs)");
- }
+ pdfi_countdown(priv->u.t1.Subrs);
- priv->u.t1.Subrs = (gs_string *) gs_alloc_bytes(mem, s->cur[0].val.i *sizeof(gs_string), "ps_font_array_func(Subrs)");
- if (priv->u.t1.Subrs == NULL) {
- return_error(gs_error_VMerror);
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_ARRAY, (unsigned int)s->cur[0].val.i, (pdf_obj **)&priv->u.t1.Subrs);
+ if (code < 0) {
+ return code;
}
- memset(priv->u.t1.Subrs, 0x00, s->cur[0].val.i * sizeof(gs_string));
+ pdfi_countup(priv->u.t1.Subrs);
}
- priv->u.t1.NumSubrs = s->cur[0].val.i;
code = pdf_ps_stack_pop(s, 1);
}
else if (pdf_ps_obj_has_type(&s->cur[-1], PDF_PS_OBJ_NAME) &&
@@ -1162,14 +1155,18 @@ pdf_ps_RD_oper_func(gs_memory_t *mem, pdf_ps_ctx_t *s, byte *buf, byte *bufend)
size = s->cur[0].val.i;
buf++;
if (buf + size < bufend) {
- priv->u.t1.Subrs[inx].data =
- gs_alloc_bytes(mem, size, "pdf_ps_RD_oper_func(subr string)");
- if (priv->u.t1.Subrs[inx].data == NULL) {
- (void)pdf_ps_stack_pop(s, 2);
- return_error(gs_error_VMerror);
+ pdf_string *subr_str;
+
+ code = pdfi_object_alloc(s->pdfi_ctx, PDF_STRING, (unsigned int)size, (pdf_obj **)&subr_str);
+ if (code < 0) {
+ return code;
}
- memcpy(priv->u.t1.Subrs[inx].data, buf, size);
- priv->u.t1.Subrs[inx].size = size;
+ memcpy(subr_str->data, buf, size);
+ pdfi_countup(subr_str);
+ code = pdfi_array_put(s->pdfi_ctx, priv->u.t1.Subrs, inx, (pdf_obj *)subr_str);
+ pdfi_countdown(subr_str);
+ if (code < 0)
+ return code;
}
}
}
@@ -1282,7 +1279,7 @@ pdfi_read_ps_font(pdf_context *ctx, pdf_dict *font_dict, byte *fbuf, int fbuflen
and that can end up in a stackoverflow error, even though we have a complete font. Override it
and let the Type 1 specific code decide for itself if it can use the font.
*/
- if (code == gs_error_stackoverflow)
+ if (code == gs_error_pdf_stackoverflow)
code = 0;
return code;
diff --git a/pdf/pdf_fontps.h b/pdf/pdf_fontps.h
index 835f0066..79ba2aef 100644
--- a/pdf/pdf_fontps.h
+++ b/pdf/pdf_fontps.h
@@ -208,7 +208,7 @@ static inline int pdf_ps_stack_push(pdf_ps_ctx_t *s)
}
s->cur++;
if (pdf_ps_obj_has_type(s->cur, PDF_PS_OBJ_STACK_TOP))
- return_error(gs_error_stackoverflow);
+ return_error(gs_error_pdf_stackoverflow);
if (pdf_ps_obj_has_type(s->cur, PDF_PS_OBJ_STACK_BOTTOM))
return_error(gs_error_stackunderflow);
return 0;
@@ -239,7 +239,7 @@ static inline int pdf_ps_stack_pop(pdf_ps_ctx_t *s, unsigned int n)
pdf_ps_make_null(s->cur);
s->cur--;
if (pdf_ps_obj_has_type(s->cur, PDF_PS_OBJ_STACK_TOP))
- return_error(gs_error_stackoverflow);
+ return_error(gs_error_pdf_stackoverflow);
if (pdf_ps_obj_has_type(s->cur, PDF_PS_OBJ_STACK_BOTTOM))
return_error(gs_error_stackunderflow);
}
diff --git a/pdf/pdf_func.c b/pdf/pdf_func.c
index 9537152e..2aaf1eea 100644
--- a/pdf/pdf_func.c
+++ b/pdf/pdf_func.c
@@ -157,6 +157,15 @@ pdfi_parse_type4_func_stream(pdf_context *ctx, pdf_c_stream *function_stream, in
if (c < 0)
break;
switch(c) {
+ case '%':
+ do {
+ c = pdfi_read_byte(ctx, function_stream);
+ if (c < 0)
+ break;
+ if (c == 0x0a || c == 0x0d)
+ break;
+ }while (1);
+ break;
case 0x20:
case 0x0a:
case 0x0d:
@@ -296,7 +305,7 @@ pdfi_build_function_4(pdf_context *ctx, gs_function_params_t * mnDR,
params.ops.data = 0; /* in case of failure */
params.ops.size = 0; /* ditto */
- if (function_obj->type != PDF_STREAM)
+ if (pdfi_type_of(function_obj) != PDF_STREAM)
return_error(gs_error_undefined);
Length = pdfi_stream_length(ctx, (pdf_stream *)function_obj);
@@ -378,7 +387,7 @@ pdfi_build_function_0(pdf_context *ctx, gs_function_params_t * mnDR,
params.Size = params.array_step = params.stream_step = NULL;
params.Order = 0;
- if (function_obj->type != PDF_STREAM)
+ if (pdfi_type_of(function_obj) != PDF_STREAM)
return_error(gs_error_undefined);
code = pdfi_dict_from_obj(ctx, (pdf_obj *)function_obj, &function_dict);
@@ -444,7 +453,7 @@ pdfi_build_function_0(pdf_context *ctx, gs_function_params_t * mnDR,
code = pdfi_make_int_array_from_dict(ctx, (int **)&params.Size, function_dict, "Size");
if (code != params.m) {
- if (code > 0)
+ if (code >= 0)
code = gs_error_rangecheck;
goto function_0_error;
}
@@ -560,6 +569,20 @@ pdfi_build_function_3(pdf_context *ctx, gs_function_params_t * mnDR,
params.Functions = (const gs_function_t * const *)ptr;
+ code = pdfi_make_float_array_from_dict(ctx, (float **)&params.Bounds, function_dict, "Bounds");
+ if (code < 0)
+ goto function_3_error;
+
+ code = pdfi_make_float_array_from_dict(ctx, (float **)&params.Encode, function_dict, "Encode");
+ if (code < 0)
+ goto function_3_error;
+
+ if (code != 2 * params.k) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto function_3_error;
+ }
+ code = 0;
+
for (i = 0; i < params.k; ++i) {
pdf_obj * rsubfn = NULL;
@@ -578,23 +601,12 @@ pdfi_build_function_3(pdf_context *ctx, gs_function_params_t * mnDR,
if (code < 0)
goto function_3_error;
- code = pdfi_build_sub_function(ctx, &ptr[i], shading_domain, num_inputs, rsubfn, page_dict);
+ code = pdfi_build_sub_function(ctx, &ptr[i], &params.Encode[i * 2], num_inputs, rsubfn, page_dict);
pdfi_countdown(rsubfn);
if (code < 0)
goto function_3_error;
}
- code = pdfi_make_float_array_from_dict(ctx, (float **)&params.Bounds, function_dict, "Bounds");
- if (code < 0)
- goto function_3_error;
-
- code = pdfi_make_float_array_from_dict(ctx, (float **)&params.Encode, function_dict, "Encode");
- if (code < 0)
- goto function_3_error;
-
- if (code != 2 * params.k)
- goto function_3_error;
-
if (params.Range == 0)
params.n = params.Functions[0]->params.n;
@@ -619,6 +631,7 @@ static int pdfi_build_sub_function(pdf_context *ctx, gs_function_t ** ppfn, cons
int64_t Type;
gs_function_params_t params;
pdf_dict *stream_dict;
+ int obj_num;
params.Range = params.Domain = NULL;
@@ -626,10 +639,11 @@ static int pdfi_build_sub_function(pdf_context *ctx, gs_function_t ** ppfn, cons
if (code < 0)
return code;
- if (stream_obj->object_num != 0) {
- if (pdfi_loop_detector_check_object(ctx, stream_obj->object_num))
+ obj_num = pdf_object_num(stream_obj);
+ if (obj_num != 0) {
+ if (pdfi_loop_detector_check_object(ctx, obj_num))
return gs_note_error(gs_error_circular_reference);
- code = pdfi_loop_detector_add_object(ctx, stream_obj->object_num);
+ code = pdfi_loop_detector_add_object(ctx, obj_num);
if (code < 0)
goto sub_function_error;
}
diff --git a/pdf/pdf_gstate.c b/pdf/pdf_gstate.c
index c1444b4b..5248bd40 100644
--- a/pdf/pdf_gstate.c
+++ b/pdf/pdf_gstate.c
@@ -44,6 +44,8 @@
#include "gscoord.h" /* For gs_concat() */
#include "gsutil.h" /* For gs_next_ids() */
#include "gscolor3.h" /* For gs_setsmoothness() */
+#include "gzpath.h"
+#include "gspenum.h"
static const char *blend_mode_names[] = {
GS_BLEND_MODE_NAMES, 0
@@ -158,8 +160,7 @@ pdfi_gstate_set_client(pdf_context *ctx, gs_gstate *pgs)
int pdfi_concat(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[6];
gs_matrix m;
@@ -171,28 +172,18 @@ int pdfi_concat(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_concat", NULL);
- for (i=0;i < 6;i++){
- num = (pdf_num *)ctx->stack_top[i - 6];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 6);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 6);
+ if (code < 0)
+ return code;
+
m.xx = (float)Values[0];
m.xy = (float)Values[1];
m.yx = (float)Values[2];
m.yy = (float)Values[3];
m.tx = (float)Values[4];
m.ty = (float)Values[5];
- code = gs_concat(ctx->pgs, (const gs_matrix *)&m);
- pdfi_pop(ctx, 6);
- return code;
+
+ return gs_concat(ctx->pgs, (const gs_matrix *)&m);
}
int pdfi_op_q(pdf_context *ctx)
@@ -216,7 +207,6 @@ int pdfi_op_q(pdf_context *ctx)
int pdfi_op_Q(pdf_context *ctx)
{
int code = 0;
- gx_path *ppath = NULL;
#if DEBUG_GSAVE
dbgmprintf(ctx->memory, "(doing Q)\n"); /* TODO: Spammy, delete me at some point */
@@ -232,30 +222,7 @@ int pdfi_op_Q(pdf_context *ctx)
return code;
}
- /* Section 4.4.1 of the 3rd Edition PDF_Refrence Manual, p226 of the 1.7 version
- * states that the current path is **NOT** part of the graphics state and is not
- * saved and restored along with the other graphics state parameters. So here
- * we need to indulge in some ugliness. We take a copy of the current path
- * before we do a grestore, and below we assign the copy to the graphics state
- * after the grestore, thus preserving it unchanged. This is still better than
- * the 'PDF interpreter written in PostScript' method.
- */
- ppath = gx_path_alloc_shared(ctx->pgs->path, ctx->memory, "temporary current path copy for Q");
- if (ppath == NULL)
- return_error(gs_error_VMerror);
-
- code = pdfi_grestore(ctx);
-
- if (code >= 0) {
- /* Put the path back, and make sure current point is properly set */
- code = gx_path_assign_preserve(ctx->pgs->path, ppath);
- if (gx_path_position_valid(ctx->pgs->path))
- gx_setcurrentpoint_from_path(ctx->pgs, ctx->pgs->path);
- }
-
- gx_path_free(ppath, "temporary current path copy for Q");
-
- return code;
+ return pdfi_grestore(ctx);
}
/* We want pdfi_grestore() so we can track and warn of "too many Qs"
@@ -296,86 +263,60 @@ int pdfi_gs_setgstate(gs_gstate * pgs, const gs_gstate * pfrom)
int pdfi_setlinewidth(pdf_context *ctx)
{
int code;
- pdf_num *n1;
double d1;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- d1 = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- d1 = n1->value.d;
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
- code = gs_setlinewidth(ctx->pgs, d1);
- pdfi_pop(ctx, 1);
- return code;
+ code = pdfi_destack_real(ctx, &d1);
+ if (code < 0)
+ return code;
+
+ return gs_setlinewidth(ctx->pgs, d1);
}
int pdfi_setlinejoin(pdf_context *ctx)
{
int code;
- pdf_num *n1;
+ int64_t i;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- code = gs_setlinejoin(ctx->pgs, n1->value.i);
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ code = pdfi_destack_int(ctx, &i);
+ if (code < 0)
+ return code;
+
+ return gs_setlinejoin(ctx->pgs, (int)i);
}
int pdfi_setlinecap(pdf_context *ctx)
{
int code;
- pdf_num *n1;
+ int64_t i;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- code = gs_setlinecap(ctx->pgs, n1->value.i);
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ code = pdfi_destack_int(ctx, &i);
+ if (code < 0)
+ return code;
+
+ return gs_setlinecap(ctx->pgs, i);
}
int pdfi_setflat(pdf_context *ctx)
{
int code;
- pdf_num *n1;
double d1;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- d1 = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- d1 = n1->value.d;
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
+ code = pdfi_destack_real(ctx, &d1);
+ if (code < 0)
+ return code;
+
/* PDF spec says the value is 1-100, with 0 meaning "use the default"
* But gs code (and now our code) forces the value to be <= 1
* This matches what Adobe and evince seem to do (see Bug 555657).
@@ -384,9 +325,7 @@ int pdfi_setflat(pdf_context *ctx)
*/
if (d1 > 1.0)
d1 = 1.0;
- code = gs_setflat(ctx->pgs, d1);
- pdfi_pop(ctx, 1);
- return code;
+ return gs_setflat(ctx->pgs, d1);
}
int pdfi_setdash_impl(pdf_context *ctx, pdf_array *a, double phase_d)
@@ -412,9 +351,9 @@ int pdfi_setdash_impl(pdf_context *ctx, pdf_array *a, double phase_d)
gs_free_object(ctx->memory, dash_array, "error in setdash");
return code;
}
+
int pdfi_setdash(pdf_context *ctx)
{
- pdf_num *phase;
pdf_array *a;
double phase_d;
int code;
@@ -424,52 +363,47 @@ int pdfi_setdash(pdf_context *ctx)
return_error(gs_error_stackunderflow);
}
- phase = (pdf_num *)ctx->stack_top[-1];
- if (phase->type == PDF_INT){
- phase_d = (double)phase->value.i;
- } else{
- if (phase->type == PDF_REAL) {
- phase_d = phase->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
+ code = pdfi_destack_real(ctx, &phase_d);
+ if (code < 0) {
+ pdfi_pop(ctx, 1);
+ return code;
}
- a = (pdf_array *)ctx->stack_top[-2];
- if (a->type != PDF_ARRAY) {
- pdfi_pop(ctx, 2);
+ a = (pdf_array *)ctx->stack_top[-1];
+ pdfi_countup(a);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(a) != PDF_ARRAY) {
+ pdfi_countdown(a);
return_error(gs_error_typecheck);
}
code = pdfi_setdash_impl(ctx, a, phase_d);
- pdfi_pop(ctx, 2);
+ pdfi_countdown(a);
return code;
}
int pdfi_setmiterlimit(pdf_context *ctx)
{
int code;
- pdf_num *n1;
double d1;
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- n1 = (pdf_num *)ctx->stack_top[-1];
- if (n1->type == PDF_INT){
- d1 = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- d1 = n1->value.d;
- } else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
- code = gs_setmiterlimit(ctx->pgs, d1);
- pdfi_pop(ctx, 1);
- return code;
+ code = pdfi_destack_real(ctx, &d1);
+ if (code < 0)
+ return code;
+
+ /* PostScript (and therefore the graphics library) impose a minimum
+ * value of 1.0 on miter limit. PDF does not specify a minimum, but less
+ * than 1 doesn't make a lot of sense. This code brought over from the old
+ * PDF interpreter which silently clamped the value to 1.
+ */
+ if (d1 < 1.0)
+ d1 = 1.0;
+
+ return gs_setmiterlimit(ctx->pgs, d1);
}
static int GS_LW(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
@@ -569,38 +503,36 @@ static int GS_RI(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
static int GS_OP(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_bool *b = NULL;
+ bool b;
int code;
bool known=false;
- code = pdfi_dict_get_type(ctx, GS, "OP", PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get_bool(ctx, GS, "OP", &b);
if (code < 0)
return code;
- gs_setstrokeoverprint(ctx->pgs, b->value);
+ gs_setstrokeoverprint(ctx->pgs, b);
/* If op not in the dict, then also set it with OP
* Because that's what gs does pdf_draw.ps/gsparamdict/OP
*/
code = pdfi_dict_known(ctx, GS, "op", &known);
if (!known)
- gs_setfilloverprint(ctx->pgs, b->value);
+ gs_setfilloverprint(ctx->pgs, b);
- pdfi_countdown(b);
return 0;
}
static int GS_op(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_bool *b;
+ bool b;
int code;
- code = pdfi_dict_get_type(ctx, GS, "op", PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get_bool(ctx, GS, "op", &b);
if (code < 0)
return code;
- gs_setfilloverprint(ctx->pgs, b->value);
- pdfi_countdown(b);
+ gs_setfilloverprint(ctx->pgs, b);
return 0;
}
@@ -652,46 +584,45 @@ static int pdfi_set_blackgeneration(pdf_context *ctx, pdf_obj *obj, pdf_dict *pa
int code = 0, i;
gs_function_t *pfn;
- if (obj->type == PDF_NAME) {
- if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
- code = gs_setblackgeneration_remap(ctx->pgs, gs_identity_transfer, false);
- goto exit;
- } else {
- if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
+ switch (pdfi_type_of(obj)) {
+ case PDF_NAME:
+ if (pdfi_name_is((const pdf_name *)obj, "Identity"))
+ code = gs_setblackgeneration_remap(ctx->pgs, gs_identity_transfer, false);
+ else if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
code = gs_setblackgeneration_remap(ctx->pgs, ctx->page.DefaultBG.proc, false);
memcpy(ctx->pgs->black_generation->values, ctx->page.DefaultBG.values, transfer_map_size * sizeof(frac));
- goto exit;
- } else {
+ } else
code = gs_note_error(gs_error_rangecheck);
- goto exit;
- }
- }
- } else {
- if (obj->type != PDF_DICT && obj->type != PDF_STREAM)
- return_error(gs_error_typecheck);
+ goto exit;
- code = pdfi_build_function(ctx, &pfn, NULL, 1, obj, page_dict);
- if (code < 0)
- return code;
+ case PDF_DICT:
+ case PDF_STREAM:
+ code = pdfi_build_function(ctx, &pfn, NULL, 1, obj, page_dict);
+ if (code < 0)
+ return code;
- gs_setblackgeneration_remap(ctx->pgs, gs_mapped_transfer, false);
- for (i = 0; i < transfer_map_size; i++) {
- float v, f;
+ gs_setblackgeneration_remap(ctx->pgs, gs_mapped_transfer, false);
+ for (i = 0; i < transfer_map_size; i++) {
+ float v, f;
- f = (1.0f / (transfer_map_size - 1)) * i;
+ f = (1.0f / (transfer_map_size - 1)) * i;
- code = gs_function_evaluate(pfn, (const float *)&f, &v);
- if (code < 0) {
- pdfi_free_function(ctx, pfn);
- return code;
+ code = gs_function_evaluate(pfn, (const float *)&f, &v);
+ if (code < 0) {
+ pdfi_free_function(ctx, pfn);
+ return code;
+ }
+
+ ctx->pgs->black_generation->values[i] =
+ (v < 0.0 ? float2frac(0.0) :
+ v >= 1.0 ? frac_1 :
+ float2frac(v));
}
+ code = pdfi_free_function(ctx, pfn);
+ break;
- ctx->pgs->black_generation->values[i] =
- (v < 0.0 ? float2frac(0.0) :
- v >= 1.0 ? frac_1 :
- float2frac(v));
- }
- code = pdfi_free_function(ctx, pfn);
+ default:
+ return_error(gs_error_typecheck);
}
exit:
return code;
@@ -741,46 +672,52 @@ static int pdfi_set_undercolorremoval(pdf_context *ctx, pdf_obj *obj, pdf_dict *
int code = 0, i;
gs_function_t *pfn;
- if (obj->type == PDF_NAME) {
- if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
- code = gs_setundercolorremoval_remap(ctx->pgs, gs_identity_transfer, false);
- goto exit;
- } else {
- if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
+ switch (pdfi_type_of(obj)) {
+ case PDF_NAME:
+ if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
+ code = gs_setundercolorremoval_remap(ctx->pgs, gs_identity_transfer, false);
+ } else if (!is_BG && pdfi_name_is((const pdf_name *)obj, "Default")) {
code = gs_setundercolorremoval_remap(ctx->pgs, ctx->page.DefaultUCR.proc, false);
memcpy(ctx->pgs->undercolor_removal->values, ctx->page.DefaultUCR.values, transfer_map_size * sizeof(frac));
- goto exit;
} else {
code = gs_note_error(gs_error_rangecheck);
- goto exit;
}
- }
- } else {
- if (obj->type != PDF_DICT && obj->type != PDF_STREAM)
- return_error(gs_error_typecheck);
+ goto exit;
- code = pdfi_build_function(ctx, &pfn, NULL, 1, obj, page_dict);
- if (code < 0)
- return code;
+ case PDF_DICT:
+ case PDF_STREAM:
+ code = pdfi_build_function(ctx, &pfn, NULL, 1, obj, page_dict);
+ if (code < 0)
+ return code;
- gs_setundercolorremoval_remap(ctx->pgs, gs_mapped_transfer, false);
- for (i = 0; i < transfer_map_size; i++) {
- float v, f;
+ if (pfn->params.n == 1) {
+ gs_setundercolorremoval_remap(ctx->pgs, gs_mapped_transfer, false);
+ for (i = 0; i < transfer_map_size; i++) {
+ float v, f;
- f = (1.0f / (transfer_map_size - 1)) * i;
+ f = (1.0f / (transfer_map_size - 1)) * i;
- code = gs_function_evaluate(pfn, (const float *)&f, &v);
- if (code < 0) {
- pdfi_free_function(ctx, pfn);
- return code;
+ code = gs_function_evaluate(pfn, (const float *)&f, &v);
+ if (code < 0) {
+ pdfi_free_function(ctx, pfn);
+ return code;
+ }
+
+ ctx->pgs->undercolor_removal->values[i] =
+ (v < 0.0 ? float2frac(0.0) :
+ v >= 1.0 ? frac_1 :
+ float2frac(v));
+ }
+ code = pdfi_free_function(ctx, pfn);
+ }
+ else {
+ (void)pdfi_free_function(ctx, pfn);
+ code = gs_note_error(gs_error_rangecheck);
}
+ break;
- ctx->pgs->undercolor_removal->values[i] =
- (v < 0.0 ? float2frac(0.0) :
- v >= 1.0 ? frac_1 :
- float2frac(v));
- }
- code = pdfi_free_function(ctx, pfn);
+ default:
+ return_error(gs_error_typecheck);
}
exit:
return code;
@@ -852,12 +789,12 @@ static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page
code = pdfi_array_get(ctx, a, (uint64_t)i, &o);
if (code < 0)
goto exit;
- if (o->type == PDF_NAME) {
- if (pdfi_name_is((const pdf_name *)o, "Identity")) {
- proc_types[i] = E_IDENTITY;
- map_procs[i] = gs_identity_transfer;
- } else {
- if (!is_TR && pdfi_name_is((const pdf_name *)o, "Default")) {
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ if (pdfi_name_is((const pdf_name *)o, "Identity")) {
+ proc_types[i] = E_IDENTITY;
+ map_procs[i] = gs_identity_transfer;
+ } else if (!is_TR && pdfi_name_is((const pdf_name *)o, "Default")) {
proc_types[i] = E_DEFAULT;
map_procs[i] = ctx->page.DefaultTransfers[i].proc;
} else {
@@ -865,9 +802,9 @@ static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page
code = gs_note_error(gs_error_typecheck);
goto exit;
}
- }
- } else {
- if (o->type == PDF_STREAM || o->type == PDF_DICT) {
+ break;
+ case PDF_STREAM:
+ case PDF_DICT:
proc_types[i] = E_FUNCTION;
map_procs[i] = gs_mapped_transfer;
code = pdfi_build_function(ctx, &pfn[i], NULL, 1, o, page_dict);
@@ -880,11 +817,11 @@ static int pdfi_set_all_transfers(pdf_context *ctx, pdf_array *a, pdf_dict *page
code = gs_note_error(gs_error_rangecheck);
goto exit;
}
- } else {
+ break;
+ default:
pdfi_countdown(o);
code = gs_note_error(gs_error_typecheck);
goto exit;
- }
}
pdfi_countdown(o);
}
@@ -954,7 +891,7 @@ static int pdfi_set_gray_transfer(pdf_context *ctx, pdf_obj *tr_obj, pdf_dict *p
int code = 0, i;
gs_function_t *pfn;
- if (tr_obj->type != PDF_DICT && tr_obj->type != PDF_STREAM)
+ if (pdfi_type_of(tr_obj) != PDF_DICT && pdfi_type_of(tr_obj) != PDF_STREAM)
return_error(gs_error_typecheck);
code = pdfi_build_function(ctx, &pfn, NULL, 1, tr_obj, page_dict);
@@ -990,7 +927,7 @@ static int pdfi_set_transfer(pdf_context *ctx, pdf_obj *obj, pdf_dict *page_dict
{
int code = 0;
- if (obj->type == PDF_NAME) {
+ if (pdfi_type_of(obj) == PDF_NAME) {
if (pdfi_name_is((const pdf_name *)obj, "Identity")) {
code = gs_settransfer_remap(ctx->pgs, gs_identity_transfer, false);
goto exit;
@@ -1006,7 +943,7 @@ static int pdfi_set_transfer(pdf_context *ctx, pdf_obj *obj, pdf_dict *page_dict
}
}
- if (obj->type == PDF_ARRAY) {
+ if (pdfi_type_of(obj) == PDF_ARRAY) {
if (pdfi_array_size((pdf_array *)obj) != 4) {
code = gs_note_error(gs_error_rangecheck);
goto exit;
@@ -1157,7 +1094,7 @@ error:
static int build_type1_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_dict *page_dict, gx_ht_order *porder, gs_halftone_component *phtc, char *name, int len, int comp_num)
{
- int code;
+ int code, i;
pdf_obj *obj = NULL, *transfer = NULL;
double f, a;
float values[2] = {0, 0}, domain[4] = {-1, 1, -1, 1}, out;
@@ -1193,46 +1130,48 @@ static int build_type1_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
}
memset(order, 0x00, sizeof(gx_ht_order));
- if (obj->type == PDF_NAME) {
- int i;
-
- if (pdfi_name_is((pdf_name *)obj, "Default")) {
- i = 0;
- } else {
- for (i = 0; i < (sizeof(spot_table) / sizeof (char *)); i++){
- if (pdfi_name_is((pdf_name *)obj, spot_table[i]))
- break;
+ switch (pdfi_type_of(obj)) {
+ case PDF_NAME:
+ if (pdfi_name_is((pdf_name *)obj, "Default")) {
+ i = 0;
+ } else {
+ for (i = 0; i < (sizeof(spot_table) / sizeof (char *)); i++) {
+ if (pdfi_name_is((pdf_name *)obj, spot_table[i]))
+ break;
+ }
+ if (i >= (sizeof(spot_table) / sizeof (char *)))
+ return gs_note_error(gs_error_rangecheck);
}
- if (i >= (sizeof(spot_table) / sizeof (char *)))
- return gs_note_error(gs_error_rangecheck);
- }
- code = pdfi_build_halftone_function(ctx, &pfn, (byte *)spot_functions[i], strlen(spot_functions[i]));
- if (code < 0)
- goto error;
- } else {
- if (obj->type == PDF_DICT || obj->type == PDF_STREAM) {
+ code = pdfi_build_halftone_function(ctx, &pfn, (byte *)spot_functions[i], strlen(spot_functions[i]));
+ if (code < 0)
+ goto error;
+ break;
+ case PDF_DICT:
+ case PDF_STREAM:
code = pdfi_build_function(ctx, &pfn, (const float *)domain, 2, obj, page_dict);
if (code < 0)
goto error;
- } else {
+ break;
+ default:
code = gs_note_error(gs_error_typecheck);
goto error;
- }
}
if (pdfi_dict_knownget(ctx, halftone_dict, "TransferFunction", &transfer) > 0) {
- if (transfer->type == PDF_NAME) {
- /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
- * names, if it's not Identity it would be an error (which we would ignore) and if
- * it is, it has no effect. So what's the point ?
- */
- } else {
- if (transfer->type == PDF_STREAM) {
+ switch (pdfi_type_of(transfer)) {
+ case PDF_NAME:
+ /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
+ * names, if it's not Identity it would be an error (which we would ignore) and if
+ * it is, it has no effect. So what's the point ?
+ */
+ break;
+ case PDF_STREAM:
pdfi_evaluate_transfer(ctx, transfer, page_dict, &pmap);
- } else {
+ break;
+ default:
/* should be an error, but we can just ignore it */
pdfi_set_warning(ctx, 0, NULL, W_PDF_TYPECHECK, "build_type1_halftone", NULL);
- }
+ break;
}
}
@@ -1557,7 +1496,7 @@ static int build_type5_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
* members.
*/
do {
- if (Key->type != PDF_NAME) {
+ if (pdfi_type_of(Key) != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto error;
}
@@ -1630,7 +1569,7 @@ static int build_type5_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
*/
ix = 1;
do {
- if (Key->type != PDF_NAME) {
+ if (pdfi_type_of(Key) != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto error;
}
@@ -1673,7 +1612,7 @@ static int build_type5_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
goto error;
break;
case 6:
- if (Value->type != PDF_STREAM) {
+ if (pdfi_type_of(Value) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto error;
}
@@ -1682,7 +1621,7 @@ static int build_type5_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
goto error;
break;
case 10:
- if (Value->type != PDF_STREAM) {
+ if (pdfi_type_of(Value) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto error;
}
@@ -1691,7 +1630,7 @@ static int build_type5_halftone(pdf_context *ctx, pdf_dict *halftone_dict, pdf_d
goto error;
break;
case 16:
- if (Value->type != PDF_STREAM) {
+ if (pdfi_type_of(Value) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto error;
}
@@ -1849,7 +1788,7 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
break;
case 6:
- if (halftone_obj->type != PDF_STREAM)
+ if (pdfi_type_of(halftone_obj) != PDF_STREAM)
return_error(gs_error_typecheck);
phtc = (gs_halftone_component *)gs_alloc_bytes(ctx->memory, sizeof(gs_halftone_component), "pdfi_do_halftone");
if (phtc == 0) {
@@ -1870,22 +1809,24 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
/* Transfer function pdht->order->transfer */
if (pdfi_dict_knownget(ctx, ((pdf_stream *)halftone_obj)->stream_dict, "TransferFunction", &transfer) > 0) {
- if (transfer->type == PDF_NAME) {
- /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
- * names, if it's not Identity it would be an error (which we would ignore) and if
- * it is, it has no effect. So what's the point ?
- */
- } else {
- if (transfer->type == PDF_STREAM) {
+ switch (pdfi_type_of(transfer)) {
+ case PDF_NAME:
+ /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
+ * names, if it's not Identity it would be an error (which we would ignore) and if
+ * it is, it has no effect. So what's the point ?
+ */
+ break;
+ case PDF_STREAM:
/* If we get an error here, we can just ignore it, and not apply the transfer */
code = pdfi_evaluate_transfer(ctx, transfer, page_dict, &pmap);
if (code >= 0) {
pdht->order.transfer = pmap;
}
- } else {
+ break;
+ default:
/* should be an error, but we can just ignore it */
pdfi_set_warning(ctx, 0, NULL, W_PDF_TYPECHECK, "do_halftone", NULL);
- }
+ break;
}
pdfi_countdown(transfer);
}
@@ -1901,7 +1842,7 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
gx_unset_both_dev_colors(ctx->pgs);
break;
case 10:
- if (halftone_obj->type != PDF_STREAM)
+ if (pdfi_type_of(halftone_obj) != PDF_STREAM)
return_error(gs_error_typecheck);
phtc = (gs_halftone_component *)gs_alloc_bytes(ctx->memory, sizeof(gs_halftone_component), "pdfi_do_halftone");
if (phtc == 0) {
@@ -1922,22 +1863,24 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
/* Transfer function pdht->order->transfer */
if (pdfi_dict_knownget(ctx, ((pdf_stream *)halftone_obj)->stream_dict, "TransferFunction", &transfer) > 0) {
- if (transfer->type == PDF_NAME) {
- /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
- * names, if it's not Identity it would be an error (which we would ignore) and if
- * it is, it has no effect. So what's the point ?
- */
- } else {
- if (transfer->type == PDF_STREAM) {
+ switch (pdfi_type_of(transfer)) {
+ case PDF_NAME:
+ /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
+ * names, if it's not Identity it would be an error (which we would ignore) and if
+ * it is, it has no effect. So what's the point ?
+ */
+ break;
+ case PDF_STREAM:
/* If we get an error here, we can just ignore it, and not apply the transfer */
code = pdfi_evaluate_transfer(ctx, transfer, page_dict, &pmap);
if (code >= 0) {
pdht->order.transfer = pmap;
}
- } else {
+ break;
+ default:
/* should be an error, but we can just ignore it */
pdfi_set_warning(ctx, 0, NULL, W_PDF_TYPECHECK, "do_halftone", NULL);
- }
+ break;
}
pdfi_countdown(transfer);
}
@@ -1953,7 +1896,7 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
gx_unset_both_dev_colors(ctx->pgs);
break;
case 16:
- if (halftone_obj->type != PDF_STREAM)
+ if (pdfi_type_of(halftone_obj) != PDF_STREAM)
return_error(gs_error_typecheck);
phtc = (gs_halftone_component *)gs_alloc_bytes(ctx->memory, sizeof(gs_halftone_component), "pdfi_do_halftone");
if (phtc == 0) {
@@ -1974,22 +1917,24 @@ static int pdfi_do_halftone(pdf_context *ctx, pdf_obj *halftone_obj, pdf_dict *p
/* Transfer function pdht->order->transfer */
if (pdfi_dict_knownget(ctx, ((pdf_stream *)halftone_obj)->stream_dict, "TransferFunction", &transfer) > 0) {
- if (transfer->type == PDF_NAME) {
- /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
- * names, if it's not Identity it would be an error (which we would ignore) and if
- * it is, it has no effect. So what's the point ?
- */
- } else {
- if (transfer->type == PDF_STREAM) {
+ switch (pdfi_type_of(transfer)) {
+ case PDF_NAME:
+ /* As far as I can tell, only /Identity is valid as a name, so we can just ignore
+ * names, if it's not Identity it would be an error (which we would ignore) and if
+ * it is, it has no effect. So what's the point ?
+ */
+ break;
+ case PDF_STREAM:
/* If we get an error here, we can just ignore it, and not apply the transfer */
code = pdfi_evaluate_transfer(ctx, transfer, page_dict, &pmap);
if (code >= 0) {
pdht->order.transfer = pmap;
}
- } else {
+ break;
+ default:
/* should be an error, but we can just ignore it */
pdfi_set_warning(ctx, 0, NULL, W_PDF_TYPECHECK, "do_halftone", NULL);
- }
+ break;
}
pdfi_countdown(transfer);
}
@@ -2034,7 +1979,7 @@ static int GS_HT(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
return code;
- if (obj->type == PDF_NAME) {
+ if (pdfi_type_of(obj) == PDF_NAME) {
if (pdfi_name_is((const pdf_name *)obj, "Default")) {
goto exit;
} else {
@@ -2044,6 +1989,10 @@ static int GS_HT(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
} else {
code = pdfi_do_halftone(ctx, obj, page_dict);
}
+ if (code < 0 && !ctx->args.pdfstoponerror) {
+ pdfi_set_error(ctx, code, NULL, E_BAD_HALFTONE, "GS_HT", "Halftone will be ignored");
+ code = 0;
+ }
exit:
pdfi_countdown(obj);
@@ -2078,33 +2027,51 @@ static int GS_SM(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
static int GS_SA(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_bool *b;
+ bool b;
int code;
- code = pdfi_dict_get_type(ctx, GS, "SA", PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get_bool(ctx, GS, "SA", &b);
if (code < 0)
return code;
- code = gs_setstrokeadjust(ctx->pgs, b->value);
- pdfi_countdown(b);
- return 0;
+ return gs_setstrokeadjust(ctx->pgs, b);
}
static int GS_BM(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
pdf_name *n;
int code;
- gs_blend_mode_t mode;
+ gs_blend_mode_t mode = 0; /* Start with /Normal */
- code = pdfi_dict_get_type(ctx, GS, "BM", PDF_NAME, (pdf_obj **)&n);
+ code = pdfi_dict_get(ctx, GS, "BM", (pdf_obj **)&n);
if (code < 0)
return code;
- code = pdfi_get_blend_mode(ctx, n, &mode);
- pdfi_countdown(n);
- if (code == 0)
+ if (pdfi_type_of(n) == PDF_ARRAY) {
+ int i;
+ pdf_array *a = (pdf_array *)n;
+
+ for (i=0;i < pdfi_array_size(a);i++){
+ code = pdfi_array_get_type(ctx, a, i, PDF_NAME, (pdf_obj **)&n);
+ if (code < 0)
+ continue;
+ code = pdfi_get_blend_mode(ctx, n, &mode);
+ pdfi_countdown(n);
+ if (code == 0)
+ break;
+ }
+ pdfi_countdown(a);
return gs_setblendmode(ctx->pgs, mode);
- return_error(gs_error_undefined);
+ }
+
+ if (pdfi_type_of(n) == PDF_NAME) {
+ code = pdfi_get_blend_mode(ctx, n, &mode);
+ pdfi_countdown(n);
+ if (code == 0)
+ return gs_setblendmode(ctx->pgs, mode);
+ return_error(gs_error_undefined);
+ }
+ return_error(gs_error_typecheck);
}
static int GS_SMask(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
@@ -2112,7 +2079,7 @@ static int GS_SMask(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_d
pdf_obj *o = NULL;
pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
int code;
- pdf_bool *Processed = NULL;
+ bool Processed;
if (ctx->page.has_transparency == false || ctx->args.notransparency == true)
return 0;
@@ -2121,40 +2088,51 @@ static int GS_SMask(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_d
if (code < 0)
return code;
- if (o->type == PDF_NAME) {
- pdf_name *n = (pdf_name *)o;
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ {
+ pdf_name *n = (pdf_name *)o;
- if (pdfi_name_is(n, "None")) {
- if (igs->SMask) {
- pdfi_gstate_smask_free(igs);
- code = pdfi_trans_end_smask_notify(ctx);
+ if (pdfi_name_is(n, "None")) {
+ if (igs->SMask) {
+ pdfi_gstate_smask_free(igs);
+ code = pdfi_trans_end_smask_notify(ctx);
+ }
+ goto exit;
}
- goto exit;
+ code = pdfi_find_resource(ctx, (unsigned char *)"ExtGState", n, stream_dict, page_dict, &o);
+ pdfi_countdown(n);
+ if (code < 0)
+ return code;
+ break;
}
- code = pdfi_find_resource(ctx, (unsigned char *)"ExtGState", n, stream_dict, page_dict, &o);
- pdfi_countdown(n);
- if (code < 0)
- return code;
- }
- if (o->type == PDF_DICT) {
- code = pdfi_dict_knownget_type(ctx, (pdf_dict *)o, "Processed", PDF_BOOL, (pdf_obj **)&Processed);
- /* Need to clear the Processed flag in the SMask if another value is set
- * (even if it's the same SMask?)
- * TODO: I think there is a better way to do this that doesn't require sticking this
- * flag in the SMask dictionary. But for now, let's get correct behavior.
- */
- if (code > 0 && Processed->value)
- Processed->value = false;
- if (igs->SMask)
- pdfi_gstate_smask_free(igs);
- /* We need to use the graphics state memory, in case we are running under Ghostscript. */
- pdfi_gstate_smask_install(igs, ctx->pgs->memory, (pdf_dict *)o, ctx->pgs);
+ case PDF_DICT:
+ {
+ code = pdfi_dict_knownget_bool(ctx, (pdf_dict *)o, "Processed", &Processed);
+ /* Need to clear the Processed flag in the SMask if another value is set
+ * (even if it's the same SMask?)
+ * TODO: I think there is a better way to do this that doesn't require sticking this
+ * flag in the SMask dictionary. But for now, let's get correct behavior.
+ */
+ if (code > 0 && Processed) {
+ code = pdfi_dict_put_bool(ctx, (pdf_dict *)o, "Processed", false);
+ if (code < 0)
+ return code;
+ }
+ if (igs->SMask)
+ pdfi_gstate_smask_free(igs);
+ /* We need to use the graphics state memory, in case we are running under Ghostscript. */
+ pdfi_gstate_smask_install(igs, ctx->pgs->memory, (pdf_dict *)o, ctx->pgs);
+ break;
+ }
+
+ default:
+ break;
}
exit:
pdfi_countdown(o);
- pdfi_countdown(Processed);
return 0;
}
@@ -2206,30 +2184,26 @@ static int GS_ca(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict
static int GS_AIS(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_bool *b;
+ bool b;
int code;
- code = pdfi_dict_get_type(ctx, GS, "AIS", PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get_bool(ctx, GS, "AIS", &b);
if (code < 0)
return code;
- code = gs_setalphaisshape(ctx->pgs, b->value);
- pdfi_countdown(b);
- return 0;
+ return gs_setalphaisshape(ctx->pgs, b);
}
static int GS_TK(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_bool *b;
+ bool b;
int code;
- code = pdfi_dict_get_type(ctx, GS, "TK", PDF_BOOL, (pdf_obj **)&b);
+ code = pdfi_dict_get_bool(ctx, GS, "TK", &b);
if (code < 0)
return code;
- code = gs_settextknockout(ctx->pgs, b->value);
- pdfi_countdown(b);
- return 0;
+ return gs_settextknockout(ctx->pgs, b);
}
typedef int (*GS_proc)(pdf_context *ctx, pdf_dict *GS, pdf_dict *stream_dict, pdf_dict *page_dict);
@@ -2293,7 +2267,7 @@ int pdfi_set_ExtGState(pdf_context *ctx, pdf_dict *stream_dict,
int pdfi_setgstate(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_name *n;
+ pdf_name *n = NULL;
pdf_obj *o = NULL;
int code=0, code1 = 0;
@@ -2306,19 +2280,20 @@ int pdfi_setgstate(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
goto setgstate_error;
}
n = (pdf_name *)ctx->stack_top[-1];
- if (n->type != PDF_NAME) {
- pdfi_pop(ctx, 1);
+ pdfi_countup(n);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(n) != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto setgstate_error;
}
code = pdfi_find_resource(ctx, (unsigned char *)"ExtGState", n, (pdf_dict *)stream_dict,
page_dict, &o);
- pdfi_pop(ctx, 1);
if (code < 0)
goto setgstate_error;
- if (o->type != PDF_DICT) {
+ if (pdfi_type_of(o) != PDF_DICT) {
code = gs_note_error(gs_error_typecheck);
goto setgstate_error;
}
@@ -2329,6 +2304,7 @@ setgstate_error:
code1 = pdfi_loop_detector_cleartomark(ctx);
if (code == 0) code = code1;
+ pdfi_countdown(n);
pdfi_countdown(o);
return code;
}
diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c
index 554cc344..43b70f56 100644
--- a/pdf/pdf_image.c
+++ b/pdf/pdf_image.c
@@ -173,7 +173,7 @@ pdfi_find_alternate(pdf_context *ctx, pdf_obj *alt)
int code;
bool flag;
- if (alt->type != PDF_ARRAY)
+ if (pdfi_type_of(alt) != PDF_ARRAY)
return NULL;
array = (pdf_array *)alt;
@@ -528,6 +528,10 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
}
info->BPC = 1;
}
+ else if (info->BPC != 1 && info->BPC != 2 && info->BPC != 4 && info->BPC != 8 && info->BPC != 16) {
+ code = gs_note_error(gs_error_rangecheck);
+ goto errorExit;
+ }
/* TODO: spec says if ImageMask is specified, and BPC is specified, then BPC must be 1
Should we flag an error if this is violated?
*/
@@ -541,11 +545,18 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
* GS implementation does.
*/
if (code != gs_error_undefined) {
- pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
if (ctx->args.pdfstoponwarning)
goto errorExit;
}
}
+ if (info->Mask != NULL && (pdfi_type_of(info->Mask) != PDF_ARRAY && pdfi_type_of(info->Mask) != PDF_STREAM)) {
+ pdfi_countdown(info->Mask);
+ info->Mask = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Optional (apparently there is no abbreviation for "SMask"? */
code = pdfi_dict_get(ctx, image_dict, "SMask", &info->SMask);
@@ -558,7 +569,7 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
code = 0;
}
} else {
- if (info->SMask->type == PDF_NAME) {
+ if (pdfi_type_of(info->SMask) == PDF_NAME) {
pdf_obj *o = NULL;
code = pdfi_find_resource(ctx, (unsigned char *)"ExtGState", (pdf_name *)info->SMask, image_dict, page_dict, &o);
@@ -568,9 +579,12 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
}
}
- if (info->SMask->type != PDF_STREAM){
+ if (pdfi_type_of(info->SMask) != PDF_STREAM){
pdfi_countdown(info->SMask);
info->SMask = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
}
}
@@ -592,6 +606,13 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->ColorSpace != NULL && (pdfi_type_of(info->ColorSpace) != PDF_NAME && pdfi_type_of(info->ColorSpace) != PDF_ARRAY)) {
+ pdfi_countdown(info->ColorSpace);
+ info->ColorSpace = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Optional (default is to use from graphics state) */
/* (no abbreviation for inline) */
@@ -607,6 +628,13 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->Alternates != NULL && pdfi_type_of(info->Alternates) != PDF_ARRAY) {
+ pdfi_countdown(info->Alternates);
+ info->Alternates = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Optional (required in PDF1.0, obsolete, do we support?) */
code = pdfi_dict_get(ctx, image_dict, "Name", &info->Name);
@@ -614,6 +642,13 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->Name != NULL && pdfi_type_of(info->Name) != PDF_NAME) {
+ pdfi_countdown(info->Name);
+ info->Name = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Required "if image is structural content item" */
/* TODO: Figure out what to do here */
@@ -629,6 +664,13 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->Decode != NULL && pdfi_type_of(info->Decode) != PDF_ARRAY) {
+ pdfi_countdown(info->Decode);
+ info->Decode = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Optional "Optional Content" */
code = pdfi_dict_get_type(ctx, image_dict, "OC", PDF_DICT, (pdf_obj **)&info->OC);
@@ -643,10 +685,17 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->Filter != NULL && (pdfi_type_of(info->Filter) != PDF_NAME && pdfi_type_of(info->Filter) != PDF_ARRAY)) {
+ pdfi_countdown(info->Filter);
+ info->Filter = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
/* Check and set JPXDecode flag for later */
info->is_JPXDecode = false;
- if (info->Filter && info->Filter->type == PDF_NAME) {
+ if (info->Filter && pdfi_type_of(info->Filter) == PDF_NAME) {
if (pdfi_name_is((pdf_name *)info->Filter, "JPXDecode"))
info->is_JPXDecode = true;
}
@@ -657,6 +706,13 @@ pdfi_get_image_info(pdf_context *ctx, pdf_stream *image_obj,
if (code != gs_error_undefined)
goto errorExit;
}
+ if (info->DecodeParms != NULL && (pdfi_type_of(info->DecodeParms) != PDF_DICT && pdfi_type_of(info->DecodeParms) != PDF_ARRAY)) {
+ pdfi_countdown(info->DecodeParms);
+ info->DecodeParms = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_IMAGEDICT, "pdfi_get_image_info", NULL);
+ if (ctx->args.pdfstoponwarning)
+ goto errorExit;
+ }
return 0;
@@ -987,6 +1043,9 @@ pdfi_do_image_smask(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *i
if (code < 0)
return code;
+ if (pdfi_type_of(image_info->SMask) != PDF_STREAM)
+ return_error(gs_error_typecheck);
+
if (image_info->SMask->object_num != 0) {
if (pdfi_loop_detector_check_object(ctx, image_info->SMask->object_num))
return gs_note_error(gs_error_circular_reference);
@@ -1018,22 +1077,23 @@ pdfi_do_image_smask(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *i
pdfi_seek(ctx, ctx->main_stream,
pdfi_stream_offset(ctx, (pdf_stream *)image_info->SMask), SEEK_SET);
- if (image_info->SMask->type == PDF_DICT) {
- code = pdfi_obj_dict_to_stream(ctx, (pdf_dict *)image_info->SMask, &stream_obj, false);
- if (code == 0) {
- code = pdfi_do_image_or_form(ctx, image_info->stream_dict,
- image_info->page_dict, (pdf_obj *)stream_obj);
+ switch (pdfi_type_of(image_info->SMask)) {
+ case PDF_DICT:
+ code = pdfi_obj_dict_to_stream(ctx, (pdf_dict *)image_info->SMask, &stream_obj, false);
+ if (code == 0) {
+ code = pdfi_do_image_or_form(ctx, image_info->stream_dict,
+ image_info->page_dict, (pdf_obj *)stream_obj);
- pdfi_countdown(stream_obj);
- }
- } else {
- if (image_info->SMask->type == PDF_STREAM)
+ pdfi_countdown(stream_obj);
+ }
+ break;
+ case PDF_STREAM:
code = pdfi_do_image_or_form(ctx, image_info->stream_dict,
image_info->page_dict, image_info->SMask);
- else {
+ break;
+ default:
code = gs_note_error(gs_error_typecheck);
goto exit;
- }
}
pdfi_seek(ctx, ctx->main_stream, savedoffset, SEEK_SET);
@@ -1434,7 +1494,7 @@ pdfi_image_get_color(pdf_context *ctx, pdf_c_stream *source, pdfi_image_info_t *
pcs, image_info->inline_image);
if (code < 0) {
dmprintf(ctx->memory, "WARNING: Image has unsupported ColorSpace ");
- if (ColorSpace->type == PDF_NAME) {
+ if (pdfi_type_of(ColorSpace) == PDF_NAME) {
pdf_name *name = (pdf_name *)ColorSpace;
char str[100];
int length = name->length;
@@ -1496,7 +1556,7 @@ pdfi_make_smask_dict(pdf_context *ctx, pdf_stream *image_stream, pdfi_image_info
goto exit;
}
- if (image_stream->type != PDF_STREAM) {
+ if (pdfi_type_of(image_stream) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -1623,7 +1683,7 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
memset(&smask_info, 0, sizeof(mask_info));
/* Make sure the image is a stream (which we will assume in later code) */
- if (image_stream->type != PDF_STREAM)
+ if (pdfi_type_of(image_stream) != PDF_STREAM)
return_error(gs_error_typecheck);
if (!inline_image) {
@@ -1867,23 +1927,26 @@ pdfi_do_image(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *stream_dict, pdf_
/* Get the Mask data either as an array or a dict, if present */
if (image_info.Mask != NULL) {
- if (image_info.Mask->type == PDF_ARRAY) {
- mask_array = (pdf_array *)image_info.Mask;
- } else if (image_info.Mask->type == PDF_STREAM) {
- mask_stream = (pdf_stream *)image_info.Mask;
- code = pdfi_get_image_info(ctx, mask_stream, page_dict,
- stream_dict, inline_image, &mask_info);
- if (code < 0)
- goto cleanupExit;
- } else {
- pdfi_countdown(image_info.Mask);
- image_info.Mask = NULL;
- pdfi_set_warning(ctx, 0, NULL, W_PDF_MASK_ERROR, "pdfi_do_image", NULL);
+ switch (pdfi_type_of(image_info.Mask)) {
+ case PDF_ARRAY:
+ mask_array = (pdf_array *)image_info.Mask;
+ break;
+ case PDF_STREAM:
+ mask_stream = (pdf_stream *)image_info.Mask;
+ code = pdfi_get_image_info(ctx, mask_stream, page_dict,
+ stream_dict, inline_image, &mask_info);
+ if (code < 0)
+ goto cleanupExit;
+ break;
+ default:
+ pdfi_countdown(image_info.Mask);
+ image_info.Mask = NULL;
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_MASK_ERROR, "pdfi_do_image", NULL);
}
}
/* Get the SMask info if we will need it (Type 3x images) */
- if (image_info.SMask && image_info.SMask->type == PDF_STREAM && ctx->device_state.preserve_smask) {
+ if (image_info.SMask && pdfi_type_of(image_info.SMask) == PDF_STREAM && ctx->device_state.preserve_smask) {
/* smask_dict non-NULL is used to flag a Type 3x image below */
smask_stream = (pdf_stream *)image_info.SMask;
code = pdfi_get_image_info(ctx, smask_stream, page_dict, stream_dict,
@@ -2305,7 +2368,7 @@ static int pdfi_form_stream_hack(pdf_context *ctx, pdf_dict *form_dict, pdf_stre
*hacked_stream = NULL;
- if (form_dict->type == PDF_STREAM)
+ if (pdfi_type_of(form_dict) == PDF_STREAM)
return 0;
if (!ctx->args.pdfstoponerror) {
@@ -2325,7 +2388,7 @@ static int pdfi_form_stream_hack(pdf_context *ctx, pdf_dict *form_dict, pdf_stre
pdfi_countup(d);
do {
code = pdfi_dict_knownget(ctx, d, "Parent", (pdf_obj **)&Parent);
- if (code > 0) {
+ if (code > 0 && pdfi_type_of(Parent) == PDF_DICT) {
if (Parent->object_num == stream_obj->object_num) {
pdfi_countdown(d);
pdfi_countdown(Parent);
@@ -2386,7 +2449,7 @@ static int pdfi_do_form(pdf_context *ctx, pdf_dict *page_dict, pdf_stream *form_
#if DEBUG_IMAGES
dbgmprintf(ctx->memory, "pdfi_do_form BEGIN\n");
#endif
- if (form_obj->type != PDF_STREAM) {
+ if (pdfi_type_of(form_obj) != PDF_STREAM) {
code = pdfi_form_stream_hack(ctx, (pdf_dict *)form_obj, &hacked_stream);
if (code < 0)
return code;
@@ -2530,10 +2593,15 @@ int pdfi_do_image_or_form(pdf_context *ctx, pdf_dict *stream_dict,
else
goto exit;
}
+ if (pdfi_type_of(n) != PDF_NAME) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+
if (pdfi_name_is(n, "Image")) {
gs_offset_t savedoffset;
- if (xobject_obj->type != PDF_STREAM) {
+ if (pdfi_type_of(xobject_obj) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -2568,14 +2636,17 @@ int pdfi_Do(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
pdf_name *n = NULL;
pdf_obj *o = NULL;
pdf_dict *sdict = NULL;
- bool known = false;
+ bool known = false, AddedParent = false;
if (pdfi_count_stack(ctx) < 1) {
code = gs_note_error(gs_error_stackunderflow);
goto exit1;
}
n = (pdf_name *)ctx->stack_top[-1];
- if (n->type != PDF_NAME) {
+ pdfi_countup(n);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(n) != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto exit1;
}
@@ -2590,7 +2661,7 @@ int pdfi_Do(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
if (code < 0)
goto exit;
- if (o->type != PDF_STREAM && o->type != PDF_DICT) {
+ if (pdfi_type_of(o) != PDF_STREAM && pdfi_type_of(o) != PDF_DICT) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -2610,9 +2681,11 @@ int pdfi_Do(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
code = pdfi_dict_put(ctx, sdict, "Parent", (pdf_obj *)stream_dict);
if (code < 0)
goto exit;
+ pdfi_countup(sdict);
+ AddedParent = true;
}
- code = pdfi_loop_detector_cleartomark(ctx);
+ (void)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.
@@ -2627,15 +2700,21 @@ 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);
+ pdfi_countdown(n);
pdfi_countdown(o);
- pdfi_pop(ctx, 1);
+ if (AddedParent == true) {
+ if (code >= 0)
+ code = pdfi_dict_delete(ctx, sdict, "Parent");
+ else
+ (void)pdfi_dict_delete(ctx, sdict, "Parent");
+ pdfi_countdown(sdict);
+ }
return code;
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(n);
pdfi_countdown(o);
- pdfi_pop(ctx, 1);
return code;
}
diff --git a/pdf/pdf_int.c b/pdf/pdf_int.c
index 9493922b..d32b3f7e 100644
--- a/pdf/pdf_int.c
+++ b/pdf/pdf_int.c
@@ -36,6 +36,7 @@
#include "pdf_trans.h"
#include "pdf_optcontent.h"
#include "pdf_sec.h"
+#include <stdlib.h>
#include "gsstate.h" /* for gs_gstate_free */
@@ -134,6 +135,7 @@ int pdfi_skip_eol(pdf_context *ctx, pdf_c_stream *s)
return 0;
if (c >= 0)
pdfi_unread_byte(ctx, s, (byte)c);
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_STREAM_BAD_KEYWORD, "pdfi_skip_eol", NULL);
return 0;
}
@@ -162,11 +164,14 @@ static float acrobat_compatible_atof(char *s)
}
if (*s == '.') {
+ float MAX = (MAX_FLOAT-9)/10;
float v = (float)i;
float n = 0;
float d = 1;
++s;
- while (*s >= '0' && *s <= '9') {
+ /* Bug 705211: Ensure that we don't overflow n here - just ignore any
+ * trailing digits after this. This will be plenty accurate enough. */
+ while (*s >= '0' && *s <= '9' && n <= MAX) {
n = 10 * n + (*s - '0');
d = 10 * d;
++s;
@@ -178,6 +183,83 @@ static float acrobat_compatible_atof(char *s)
}
}
+int pdfi_read_bare_int(pdf_context *ctx, pdf_c_stream *s, int *parsed_int)
+{
+ int index = 0;
+ int int_val = 0;
+ int negative = 0;
+
+restart:
+ pdfi_skip_white(ctx, s);
+
+ do {
+ int c = pdfi_read_byte(ctx, s);
+ if (c == EOFC)
+ break;
+
+ if (c < 0)
+ return_error(gs_error_ioerror);
+
+ if (iswhite(c)) {
+ break;
+ } else if (c == '%' && index == 0) {
+ pdfi_skip_comment(ctx, s);
+ goto restart;
+ } else if (isdelimiter(c)) {
+ pdfi_unread_byte(ctx, s, (byte)c);
+ break;
+ }
+
+ if (c >= '0' && c <= '9') {
+ int_val = int_val*10 + c - '0';
+ } else if (c == '.') {
+ goto error;
+ } else if (c == 'e' || c == 'E') {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_NUM_EXPONENT, "pdfi_read_num", NULL);
+ goto error;
+ } else if (c == '-') {
+ /* Any - sign not at the start of the string indicates a malformed number. */
+ if (index != 0 || negative) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", NULL);
+ if (ctx->args.pdfstoponerror)
+ return_error(gs_error_syntaxerror);
+ goto error;
+ }
+ negative = 1;
+ } else if (c == '+') {
+ if (index == 0) {
+ /* Just drop the + it's pointless, and it'll get in the way
+ * of our negation handling for floats. */
+ continue;
+ } else {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_MALFORMEDNUMBER, "pdfi_read_num", NULL);
+ if (ctx->args.pdfstoponerror)
+ return_error(gs_error_syntaxerror);
+ goto error;
+ }
+ } else {
+ if (index > 0) {
+ 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_byte(ctx, s, (byte)c);
+ goto error;
+ }
+ if (++index > 255)
+ return_error(gs_error_syntaxerror);
+ } while(1);
+
+ *parsed_int = negative ? -int_val : int_val;
+ if (ctx->args.pdfdebug)
+ dmprintf1(ctx->memory, " %d", *parsed_int);
+ return (index > 0);
+
+error:
+ *parsed_int = 0;
+ return_error(gs_error_syntaxerror);
+}
+
static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
{
byte Buffer[256];
@@ -297,12 +379,29 @@ static int pdfi_read_num(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_nu
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 (has_exponent) {
- float f;
- if (sscanf((char *)Buffer, "%g", &f) == 1) {
- num->value.d = f;
- } else {
+ float f, exp;
+ char *p = strstr((const char *)Buffer, "e");
+
+ if (p == NULL)
+ p = strstr((const char *)Buffer, "E");
+
+ if (p == NULL) {
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 {
+ p++;
+
+ if (sscanf((char *)p, "%g", &exp) != 1 || exp > 38) {
+ 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 (sscanf((char *)Buffer, "%g", &f) == 1) {
+ num->value.d = f;
+ } else {
+ 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);
@@ -443,6 +542,22 @@ static int pdfi_read_hexstring(pdf_context *ctx, pdf_c_stream *s, uint32_t indir
if (hex1 < 0)
break;
+ if (hex1 == '>') {
+ /* PDF Reference 1.7 page 56:
+ * "If the final digit of a hexadecimal string is missing that is,
+ * if there is an odd number of digits the final digit is assumed to be 0."
+ */
+ hex1 = 0x30;
+ if (!ishex(hex0) || !ishex(hex1)) {
+ code = gs_note_error(gs_error_syntaxerror);
+ goto exit;
+ }
+ Buffer[index] = (fromhex(hex0) << 4) + fromhex(hex1);
+ if (ctx->args.pdfdebug)
+ dmprintf1(ctx->memory, "%c", hex1);
+ break;
+ }
+
if (!ishex(hex0) || !ishex(hex1)) {
code = gs_note_error(gs_error_syntaxerror);
goto exit;
@@ -674,7 +789,7 @@ int pdfi_read_dict(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uin
if (code == 0)
return_error(gs_error_syntaxerror);
- if (ctx->stack_top[-1]->type != PDF_DICT_MARK)
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_DICT_MARK)
return_error(gs_error_typecheck);
depth = pdfi_count_stack(ctx);
@@ -708,18 +823,22 @@ int pdfi_skip_comment(pdf_context *ctx, pdf_c_stream *s)
return 0;
}
-/* This function is slightly misnamed, for some keywords we do
- * indeed read the keyword and return a PDF_KEYWORD object, but
- * for null, true, false and R we create an appropriate object
- * of that type (PDF_NULL, PDF_BOOL or PDF_INDIRECT_REF)
- * and return it instead.
- */
-static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
+#define PARAM1(A) # A,
+#define PARAM2(A,B) A,
+static const char pdf_token_strings[][10] = {
+#include "pdf_tokens.h"
+};
+
+#define nelems(A) (sizeof(A)/sizeof(A[0]))
+
+typedef int (*bsearch_comparator)(const void *, const void *);
+
+int pdfi_read_bare_keyword(pdf_context *ctx, pdf_c_stream *s)
{
byte Buffer[256];
- unsigned short index = 0;
- int c, code;
- pdf_keyword *keyword;
+ int index = 0;
+ int c;
+ void *t;
pdfi_skip_white(ctx, s);
@@ -739,46 +858,94 @@ static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirec
if (index >= 255 || index == 0) {
if (ctx->args.pdfstoponerror)
return_error(gs_error_syntaxerror);
- strcpy((char *)Buffer, "KEYWORD_TOO_LONG");
- index = 16;
+ return TOKEN_INVALID_KEY;
}
- /* NB The code below uses 'Buffer', not the data stored in keyword->data to compare strings */
Buffer[index] = 0x00;
+ t = bsearch((const void *)Buffer,
+ (const void *)pdf_token_strings[TOKEN_INVALID_KEY+1],
+ nelems(pdf_token_strings)-(TOKEN_INVALID_KEY+1),
+ sizeof(pdf_token_strings[0]),
+ (bsearch_comparator)&strcmp);
+ if (t == NULL)
+ return TOKEN_INVALID_KEY;
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, index, (pdf_obj **)&keyword);
- if (code < 0)
- return code;
+ if (ctx->args.pdfdebug)
+ dmprintf1(ctx->memory, " %s\n", Buffer);
- memcpy(keyword->data, Buffer, index);
- pdfi_countup(keyword);
+ return (((const char *)t) - pdf_token_strings[0]) / sizeof(pdf_token_strings[0]);
+}
- keyword->indirect_num = indirect_num;
- keyword->indirect_gen = indirect_gen;
+static pdf_key lookup_keyword(const byte *Buffer)
+{
+ void *t = bsearch((const void *)Buffer,
+ (const void *)pdf_token_strings[TOKEN_INVALID_KEY+1],
+ nelems(pdf_token_strings)-(TOKEN_INVALID_KEY+1),
+ sizeof(pdf_token_strings[0]),
+ (bsearch_comparator)&strcmp);
+ if (t == NULL)
+ return TOKEN_NOT_A_KEYWORD;
+
+ return (pdf_key)((((const char *)t) - pdf_token_strings[0]) /
+ sizeof(pdf_token_strings[0]));
+}
- if (ctx->args.pdfdebug)
- dmprintf1(ctx->memory, " %s\n", Buffer);
+/* This function is slightly misnamed. We read 'keywords' from
+ * the stream (including null, true, false and R), and will usually
+ * return them directly as TOKENs cast to be pointers. In the event
+ * that we can't match what we parse to a known keyword, we'll
+ * instead return a PDF_KEYWORD object. In the even that we parse
+ * an 'R', we will return a PDF_INDIRECT object.
+ */
+static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen)
+{
+ byte Buffer[256];
+ unsigned short index = 0;
+ int c, code;
+ pdf_keyword *keyword;
+ pdf_key key;
- switch(Buffer[0]) {
- case 'K':
- if (keyword->length == 16 && memcmp(keyword->data, "KEYWORD_TOO_LONG", 16) == 0) {
- keyword->key = TOKEN_INVALID_KEY;
- }
+ pdfi_skip_white(ctx, s);
+
+ do {
+ c = pdfi_read_byte(ctx, s);
+ if (c < 0)
+ break;
+
+ if (iswhite(c) || isdelimiter(c)) {
+ pdfi_unread_byte(ctx, s, (byte)c);
break;
- case 'R':
- if (keyword->length == 1){
+ }
+ Buffer[index] = (byte)c;
+ index++;
+ } while (index < 255);
+
+ if (index >= 255 || index == 0) {
+ if (ctx->args.pdfstoponerror)
+ return_error(gs_error_syntaxerror);
+ key = (index >= 255 ? TOKEN_TOO_LONG : TOKEN_INVALID_KEY);
+ index = 0;
+ Buffer[0] = 0;
+ } else {
+ Buffer[index] = 0x00;
+ key = lookup_keyword(Buffer);
+
+ if (ctx->args.pdfdebug)
+ dmprintf1(ctx->memory, " %s\n", Buffer);
+
+ switch (key) {
+ case TOKEN_R:
+ {
pdf_indirect_ref *o;
uint64_t obj_num;
uint32_t gen_num;
- pdfi_countdown(keyword);
-
if(pdfi_count_stack(ctx) < 2) {
pdfi_clearstack(ctx);
return_error(gs_error_stackunderflow);
}
- if(((pdf_obj *)ctx->stack_top[-1])->type != PDF_INT || ((pdf_obj *)ctx->stack_top[-2])->type != PDF_INT) {
+ if(pdfi_type_of(ctx->stack_top[-1]) != PDF_INT || pdfi_type_of(ctx->stack_top[-2]) != PDF_INT) {
pdfi_clearstack(ctx);
return_error(gs_error_typecheck);
}
@@ -803,104 +970,43 @@ static int pdfi_read_keyword(pdf_context *ctx, pdf_c_stream *s, uint32_t indirec
return code;
}
- break;
- case 'e':
- if (keyword->length == 9 && memcmp((const char *)Buffer, "endstream", 9) == 0)
- keyword->key = TOKEN_ENDSTREAM;
- else {
- if (keyword->length == 6 && memcmp((const char *)Buffer, "endobj", 6) == 0)
- keyword->key = TOKEN_ENDOBJ;
- }
- break;
- case 'o':
- if (keyword->length == 3 && memcmp((const char *)Buffer, "obj", 3) == 0)
- keyword->key = TOKEN_OBJ;
- break;
- case 's':
- if (keyword->length == 6 && memcmp((const char *)Buffer, "stream", 6) == 0){
- keyword->key = TOKEN_STREAM;
+ case TOKEN_NOT_A_KEYWORD:
+ /* Unexpected keyword found. We'll allocate an object for the buffer below. */
+ break;
+ case TOKEN_STREAM:
code = pdfi_skip_eol(ctx, s);
- if (code < 0) {
- pdfi_countdown(keyword);
- return code;
- }
- }
- else {
- if (keyword->length == 9 && memcmp((const char *)Buffer, "startxref", 9) == 0)
- keyword->key = TOKEN_STARTXREF;
- }
- break;
- case 't':
- if (keyword->length == 4 && memcmp((const char *)Buffer, "true", 4) == 0) {
- pdf_bool *o;
-
- pdfi_countdown(keyword);
-
- code = pdfi_object_alloc(ctx, PDF_BOOL, 0, (pdf_obj **)&o);
- if (code < 0)
- return code;
-
- o->value = true;
- o->indirect_num = indirect_num;
- o->indirect_gen = indirect_gen;
-
- code = pdfi_push(ctx, (pdf_obj *)o);
- if (code < 0)
- pdfi_free_object((pdf_obj *)o);
- return code;
- }
- else {
- if (keyword->length == 7 && memcmp((const char *)Buffer, "trailer", 7) == 0)
- keyword->key = TOKEN_TRAILER;
- }
- break;
- case 'f':
- if (keyword->length == 5 && memcmp((const char *)Buffer, "false", 5) == 0)
- {
- pdf_bool *o;
-
- pdfi_countdown(keyword);
-
- code = pdfi_object_alloc(ctx, PDF_BOOL, 0, (pdf_obj **)&o);
if (code < 0)
return code;
+ /* fallthrough */
+ case TOKEN_TRUE:
+ case TOKEN_FALSE:
+ case TOKEN_null:
+ default:
+ /* This is the fast, common exit case. We just push the key
+ * onto the stack. No allocation required. No deallocation
+ * in the case of error. */
+ return pdfi_push(ctx, (pdf_obj *)(intptr_t)key);
+ }
+ }
- o->value = false;
- o->indirect_num = indirect_num;
- o->indirect_gen = indirect_gen;
-
- code = pdfi_push(ctx, (pdf_obj *)o);
- if (code < 0)
- pdfi_free_object((pdf_obj *)o);
- return code;
- }
- break;
- case 'n':
- if (keyword->length == 4 && memcmp((const char *)Buffer, "null", 4) == 0){
- pdf_obj *o;
+ /* Unexpected keyword. We can't handle this with the fast no-allocation case. */
+ code = pdfi_object_alloc(ctx, PDF_KEYWORD, index, (pdf_obj **)&keyword);
+ if (code < 0)
+ return code;
- pdfi_countdown(keyword);
+ if (index)
+ memcpy(keyword->data, Buffer, index);
- code = pdfi_object_alloc(ctx, PDF_NULL, 0, &o);
- if (code < 0)
- return code;
- o->indirect_num = indirect_num;
- o->indirect_gen = indirect_gen;
+ /* keyword->length set as part of allocation. */
+ keyword->indirect_num = indirect_num;
+ keyword->indirect_gen = indirect_gen;
- code = pdfi_push(ctx, o);
- if (code < 0)
- pdfi_free_object((pdf_obj *)o);
- return code;
- }
- break;
- case 'x':
- if (keyword->length == 4 && memcmp((const char *)Buffer, "xref", 4) == 0)
- keyword->key = TOKEN_XREF;
- break;
- }
+ if (ctx->args.pdfdebug)
+ dmprintf1(ctx->memory, " %s\n", Buffer);
code = pdfi_push(ctx, (pdf_obj *)keyword);
- pdfi_countdown(keyword);
+ if (code < 0)
+ pdfi_free_object((pdf_obj *)keyword);
return code;
}
@@ -957,6 +1063,8 @@ rescan:
c = pdfi_read_byte(ctx, s);
}
if (c == '<') {
+ if (ctx->object_nesting < MAX_NESTING_DEPTH)
+ ctx->object_nesting++;
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, " <<\n");
code = pdfi_mark_stack(ctx, PDF_DICT_MARK);
@@ -983,9 +1091,14 @@ rescan:
if (c < 0)
return (gs_error_ioerror);
if (c == '>') {
- code = pdfi_dict_from_stack(ctx, indirect_num, indirect_gen, false);
- if (code < 0)
- return code;
+ if (ctx->object_nesting > 0)
+ ctx->object_nesting--;
+ if (ctx->object_nesting < MAX_NESTING_DEPTH) {
+ code = pdfi_dict_from_stack(ctx, indirect_num, indirect_gen, false);
+ if (code < 0)
+ return code;
+ } else
+ pdfi_set_error(ctx, 0, NULL, E_PDF_NESTEDTOODEEP, "pdfi_read_token", NULL);
return 1;
} else {
pdfi_unread_byte(ctx, s, (byte)c);
@@ -999,6 +1112,8 @@ rescan:
return 1;
break;
case '[':
+ if (ctx->object_nesting < MAX_NESTING_DEPTH)
+ ctx->object_nesting++;
if (ctx->args.pdfdebug)
dmprintf (ctx->memory, "[");
code = pdfi_mark_stack(ctx, PDF_ARRAY_MARK);
@@ -1007,9 +1122,14 @@ rescan:
return 1;
break;
case ']':
- code = pdfi_array_from_stack(ctx, indirect_num, indirect_gen);
- if (code < 0)
- return code;
+ if (ctx->object_nesting > 0)
+ ctx->object_nesting--;
+ if (ctx->object_nesting < MAX_NESTING_DEPTH) {
+ code = pdfi_array_from_stack(ctx, indirect_num, indirect_gen);
+ if (code < 0)
+ return code;
+ } else
+ pdfi_set_error(ctx, 0, NULL, E_PDF_NESTEDTOODEEP, "pdfi_read_token", NULL);
break;
case '{':
if (ctx->args.pdfdebug)
@@ -1080,56 +1200,63 @@ static char op_table_1[27][1] = {
static int pdfi_interpret_stream_operator(pdf_context *ctx, pdf_c_stream *source,
pdf_dict *stream_dict, pdf_dict *page_dict);
+static int
+make_keyword_obj(pdf_context *ctx, const byte *data, int length, pdf_keyword **pkey)
+{
+ byte Buffer[256];
+ pdf_key key;
+ int code;
+
+ memcpy(Buffer, data, length);
+ Buffer[length] = 0;
+ key = lookup_keyword(Buffer);
+ if (key != TOKEN_INVALID_KEY) {
+ /* The common case. We've found a real key, just cast the token to
+ * a pointer, and return that. */
+ *pkey = (pdf_keyword *)PDF_TOKEN_AS_OBJ(key);
+ return 1;
+ }
+ /* We still haven't found a real keyword. Allocate a new object and
+ * return it. */
+ code = pdfi_object_alloc(ctx, PDF_KEYWORD, length, (pdf_obj **)pkey);
+ if (code < 0)
+ return code;
+ if (length)
+ memcpy((*pkey)->data, Buffer, length);
+ pdfi_countup(*pkey);
+
+ return 1;
+}
+
static int search_table_3(pdf_context *ctx, unsigned char *str, pdf_keyword **key)
{
- int i, code = 0;
+ int i;
for (i = 0; i < 5; i++) {
- if (memcmp(str, op_table_3[i], 3) == 0) {
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, 3, (pdf_obj **)key);
- if (code < 0)
- return code;
- memcpy((*key)->data, str, 3);
- (*key)->key = TOKEN_NOT_A_KEYWORD;
- pdfi_countup(*key);
- return 1;
- }
+ if (memcmp(str, op_table_3[i], 3) == 0)
+ return make_keyword_obj(ctx, str, 3, key);
}
return 0;
}
static int search_table_2(pdf_context *ctx, unsigned char *str, pdf_keyword **key)
{
- int i, code = 0;
+ int i;
for (i = 0; i < 39; i++) {
- if (memcmp(str, op_table_2[i], 2) == 0) {
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, 2, (pdf_obj **)key);
- if (code < 0)
- return code;
- memcpy((*key)->data, str, 2);
- (*key)->key = TOKEN_NOT_A_KEYWORD;
- pdfi_countup(*key);
- return 1;
- }
+ if (memcmp(str, op_table_2[i], 2) == 0)
+ return make_keyword_obj(ctx, str, 2, key);
}
return 0;
}
static int search_table_1(pdf_context *ctx, unsigned char *str, pdf_keyword **key)
{
- int i, code = 0;
+ int 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)
- return code;
- memcpy((*key)->data, str, 1);
- (*key)->key = TOKEN_NOT_A_KEYWORD;
- pdfi_countup(*key);
- return 1;
- }
+ if (memcmp(str, op_table_1[i], 1) == 0)
+ return make_keyword_obj(ctx, str, 1, key);
}
return 0;
}
@@ -1138,45 +1265,41 @@ static int split_bogus_operator(pdf_context *ctx, pdf_c_stream *source, pdf_dict
{
int code = 0;
pdf_keyword *keyword = (pdf_keyword *)ctx->stack_top[-1], *key1 = NULL, *key2 = NULL;
+ int length = keyword->length - 6;
- if (keyword->length > 6) {
+ if (length > 0) {
/* Longer than 2 3-character operators, we only allow for up to two
* operators. Check to see if it includes an endstream or endobj.
*/
- if (memcmp(&keyword->data[keyword->length - 6], "endobj", 6) == 0) {
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, keyword->length - 6, (pdf_obj **)&key1);
+ if (memcmp(&keyword->data[length], "endobj", 6) == 0) {
+ /* Keyword is "<something>endobj". So make a keyword just from
+ * <something>, push that, execute it, then push endobj. */
+ code = make_keyword_obj(ctx, keyword->data, length, &key1);
if (code < 0)
goto error_exit;
- memcpy(key1->data, keyword->data, key1->length);
pdfi_pop(ctx, 1);
pdfi_push(ctx, (pdf_obj *)key1);
+ pdfi_countdown(key1); /* Drop the reference returned by make_keyword_obj. */
code = pdfi_interpret_stream_operator(ctx, source, stream_dict, page_dict);
if (code < 0)
goto error_exit;
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, 6, (pdf_obj **)&key1);
- if (code < 0)
- goto error_exit;
- memcpy(key1->data, "endobj", 6);
- key1->key = TOKEN_ENDOBJ;
- pdfi_push(ctx, (pdf_obj *)key1);
+ pdfi_push(ctx, PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ));
return 0;
} else {
- if (keyword->length > 9 && memcmp(&keyword->data[keyword->length - 9], "endstream", 9) == 0) {
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, keyword->length - 9, (pdf_obj **)&key1);
+ length = keyword->length - 9;
+ if (length > 0 && memcmp(&keyword->data[length], "endstream", 9) == 0) {
+ /* Keyword is "<something>endstream". So make a keyword just from
+ * <something>, push that, execute it, then push endstream. */
+ code = make_keyword_obj(ctx, keyword->data, length, &key1);
if (code < 0)
goto error_exit;
- memcpy(key1->data, keyword->data, key1->length);
pdfi_pop(ctx, 1);
pdfi_push(ctx, (pdf_obj *)key1);
+ pdfi_countdown(key1); /* Drop the reference returned by make_keyword_obj. */
code = pdfi_interpret_stream_operator(ctx, source, stream_dict, page_dict);
if (code < 0)
goto error_exit;
- code = pdfi_object_alloc(ctx, PDF_KEYWORD, 9, (pdf_obj **)&key1);
- if (code < 0)
- goto error_exit;
- memcpy(key1->data, "endstream", 9);
- key1->key = TOKEN_ENDSTREAM;
- pdfi_push(ctx, (pdf_obj *)key1);
+ pdfi_push(ctx, PDF_TOKEN_AS_OBJ(TOKEN_ENDSTREAM));
return 0;
} else {
pdfi_clearstack(ctx);
@@ -1191,15 +1314,15 @@ static int split_bogus_operator(pdf_context *ctx, pdf_c_stream *source, pdf_dict
goto error_exit;
if (code > 0) {
- switch(keyword->length - 3) {
+ switch (keyword->length - 3) {
case 1:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_1(ctx, &keyword->data[3], &key2);
break;
case 2:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_2(ctx, &keyword->data[3], &key2);
break;
case 3:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_3(ctx, &keyword->data[3], &key2);
break;
default:
goto error_exit;
@@ -1225,13 +1348,13 @@ static int split_bogus_operator(pdf_context *ctx, pdf_c_stream *source, pdf_dict
if (code > 0) {
switch(keyword->length - 2) {
case 1:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_1(ctx, &keyword->data[2], &key2);
break;
case 2:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_2(ctx, &keyword->data[2], &key2);
break;
case 3:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_3(ctx, &keyword->data[2], &key2);
break;
default:
goto error_exit;
@@ -1255,13 +1378,13 @@ static int split_bogus_operator(pdf_context *ctx, pdf_c_stream *source, pdf_dict
switch(keyword->length - 1) {
case 1:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_1(ctx, &keyword->data[1], &key2);
break;
case 2:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_2(ctx, &keyword->data[1], &key2);
break;
case 3:
- code = search_table_1(ctx, &keyword->data[key1->length], &key2);
+ code = search_table_3(ctx, &keyword->data[1], &key2);
break;
default:
goto error_exit;
@@ -1289,354 +1412,353 @@ error_exit:
return code;
}
-#define K1(a) (a)
-#define K2(a, b) ((a << 8) + b)
-#define K3(a, b, c) ((a << 16) + (b << 8) + c)
-
static int pdfi_interpret_stream_operator(pdf_context *ctx, pdf_c_stream *source,
pdf_dict *stream_dict, pdf_dict *page_dict)
{
- pdf_keyword *keyword = (pdf_keyword *)ctx->stack_top[-1];
- uint32_t op = 0;
- int i, code = 0;
+ pdf_obj *keyword = ctx->stack_top[-1];
+ int code = 0;
- if (keyword->length > 3) {
- /* This means we either have a corrupted or illegal operator. The most
- * usual corruption is two concatented operators (eg QBT instead of Q BT)
- * I plan to tackle this by trying to see if I can make two or more operators
- * out of the mangled one. Note this will also be done below in the 'default'
- * case where we don't recognise a keyword with 3 or fewer characters.
- */
- code = split_bogus_operator(ctx, source, stream_dict, page_dict);
- if (code < 0)
- return code;
- if (pdfi_count_stack(ctx) > 0) {
- keyword = (pdf_keyword *)ctx->stack_top[-1];
- if (keyword->key != TOKEN_NOT_A_KEYWORD)
- return REPAIRED_KEYWORD;
- } else
- return 0;
- } else {
- for (i=0;i < keyword->length;i++) {
- op = (op << 8) + keyword->data[i];
- }
- switch(op) {
- case K1('b'): /* closepath, fill, stroke */
+ if (keyword < PDF_TOKEN_AS_OBJ(TOKEN__LAST_KEY))
+ {
+ switch((uintptr_t)keyword) {
+ case TOKEN_b: /* closepath, fill, stroke */
pdfi_pop(ctx, 1);
code = pdfi_b(ctx);
break;
- case K1('B'): /* fill, stroke */
+ case TOKEN_B: /* fill, stroke */
pdfi_pop(ctx, 1);
code = pdfi_B(ctx);
break;
- case K2('b','*'): /* closepath, eofill, stroke */
+ case TOKEN_bstar: /* closepath, eofill, stroke */
pdfi_pop(ctx, 1);
code = pdfi_b_star(ctx);
break;
- case K2('B','*'): /* eofill, stroke */
+ case TOKEN_Bstar: /* eofill, stroke */
pdfi_pop(ctx, 1);
code = pdfi_B_star(ctx);
break;
- case K2('B','I'): /* begin inline image */
+ case TOKEN_BI: /* begin inline image */
pdfi_pop(ctx, 1);
code = pdfi_BI(ctx);
break;
- case K3('B','D','C'): /* begin marked content sequence with property list */
+ case TOKEN_BDC: /* begin marked content sequence with property list */
pdfi_pop(ctx, 1);
code = pdfi_op_BDC(ctx, stream_dict, page_dict);
break;
- case K3('B','M','C'): /* begin marked content sequence */
+ case TOKEN_BMC: /* begin marked content sequence */
pdfi_pop(ctx, 1);
code = pdfi_op_BMC(ctx);
break;
- case K2('B','T'): /* begin text */
+ case TOKEN_BT: /* begin text */
pdfi_pop(ctx, 1);
code = pdfi_BT(ctx);
break;
- case K2('B','X'): /* begin compatibility section */
+ case TOKEN_BX: /* begin compatibility section */
pdfi_pop(ctx, 1);
break;
- case K1('c'): /* curveto */
+ case TOKEN_c: /* curveto */
pdfi_pop(ctx, 1);
code = pdfi_curveto(ctx);
break;
- case K2('c','m'): /* concat */
+ case TOKEN_cm: /* concat */
pdfi_pop(ctx, 1);
code = pdfi_concat(ctx);
break;
- case K2('C','S'): /* set stroke colour space */
+ case TOKEN_CS: /* set stroke colour space */
pdfi_pop(ctx, 1);
code = pdfi_setstrokecolor_space(ctx, stream_dict, page_dict);
break;
- case K2('c','s'): /* set non-stroke colour space */
+ case TOKEN_cs: /* set non-stroke colour space */
pdfi_pop(ctx, 1);
code = pdfi_setfillcolor_space(ctx, stream_dict, page_dict);
break;
- break;
- case K1('d'): /* set dash params */
+ case TOKEN_d: /* set dash params */
pdfi_pop(ctx, 1);
code = pdfi_setdash(ctx);
break;
- case K2('d','0'): /* set type 3 font glyph width */
+ case TOKEN_d0: /* set type 3 font glyph width */
pdfi_pop(ctx, 1);
code = pdfi_d0(ctx);
break;
- case K2('d','1'): /* set type 3 font glyph width and bounding box */
+ case TOKEN_d1: /* set type 3 font glyph width and bounding box */
pdfi_pop(ctx, 1);
code = pdfi_d1(ctx);
break;
- case K2('D','o'): /* invoke named XObject */
+ case TOKEN_Do: /* invoke named XObject */
pdfi_pop(ctx, 1);
code = pdfi_Do(ctx, stream_dict, page_dict);
break;
- case K2('D','P'): /* define marked content point with property list */
+ case TOKEN_DP: /* define marked content point with property list */
pdfi_pop(ctx, 1);
code = pdfi_op_DP(ctx, stream_dict, page_dict);
break;
- case K2('E','I'): /* end inline image */
+ case TOKEN_EI: /* end inline image */
pdfi_pop(ctx, 1);
code = pdfi_EI(ctx);
break;
- case K2('E','T'): /* end text */
+ case TOKEN_ET: /* end text */
pdfi_pop(ctx, 1);
code = pdfi_ET(ctx);
break;
- case K3('E','M','C'): /* end marked content sequence */
+ case TOKEN_EMC: /* end marked content sequence */
pdfi_pop(ctx, 1);
code = pdfi_op_EMC(ctx);
break;
- case K2('E','X'): /* end compatibility section */
+ case TOKEN_EX: /* end compatibility section */
pdfi_pop(ctx, 1);
break;
- case K1('f'): /* fill */
+ case TOKEN_f: /* fill */
pdfi_pop(ctx, 1);
code = pdfi_fill(ctx);
break;
- case K1('F'): /* fill (obselete operator) */
+ case TOKEN_F: /* fill (obselete operator) */
pdfi_pop(ctx, 1);
code = pdfi_fill(ctx);
break;
- case K2('f','*'): /* eofill */
+ case TOKEN_fstar: /* eofill */
pdfi_pop(ctx, 1);
code = pdfi_eofill(ctx);
break;
- case K1('G'): /* setgray for stroke */
+ case TOKEN_G: /* setgray for stroke */
pdfi_pop(ctx, 1);
code = pdfi_setgraystroke(ctx);
break;
- case K1('g'): /* setgray for non-stroke */
+ case TOKEN_g: /* setgray for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setgrayfill(ctx);
break;
- case K2('g','s'): /* set graphics state from dictionary */
+ case TOKEN_gs: /* set graphics state from dictionary */
pdfi_pop(ctx, 1);
code = pdfi_setgstate(ctx, stream_dict, page_dict);
break;
- case K1('h'): /* closepath */
+ case TOKEN_h: /* closepath */
pdfi_pop(ctx, 1);
code = pdfi_closepath(ctx);
break;
- case K1('i'): /* setflat */
+ case TOKEN_i: /* setflat */
pdfi_pop(ctx, 1);
code = pdfi_setflat(ctx);
break;
- case K2('I','D'): /* begin inline image data */
+ case TOKEN_ID: /* begin inline image data */
pdfi_pop(ctx, 1);
code = pdfi_ID(ctx, stream_dict, page_dict, source);
break;
- case K1('j'): /* setlinejoin */
+ case TOKEN_j: /* setlinejoin */
pdfi_pop(ctx, 1);
code = pdfi_setlinejoin(ctx);
break;
- case K1('J'): /* setlinecap */
+ case TOKEN_J: /* setlinecap */
pdfi_pop(ctx, 1);
code = pdfi_setlinecap(ctx);
break;
- case K1('K'): /* setcmyk for non-stroke */
+ case TOKEN_K: /* setcmyk for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setcmykstroke(ctx);
break;
- case K1('k'): /* setcmyk for non-stroke */
+ case TOKEN_k: /* setcmyk for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setcmykfill(ctx);
break;
- case K1('l'): /* lineto */
+ case TOKEN_l: /* lineto */
pdfi_pop(ctx, 1);
code = pdfi_lineto(ctx);
break;
- case K1('m'): /* moveto */
+ case TOKEN_m: /* moveto */
pdfi_pop(ctx, 1);
code = pdfi_moveto(ctx);
break;
- case K1('M'): /* setmiterlimit */
+ case TOKEN_M: /* setmiterlimit */
pdfi_pop(ctx, 1);
code = pdfi_setmiterlimit(ctx);
break;
- case K2('M','P'): /* define marked content point */
+ case TOKEN_MP: /* define marked content point */
pdfi_pop(ctx, 1);
code = pdfi_op_MP(ctx);
break;
- case K1('n'): /* newpath */
+ case TOKEN_n: /* newpath */
pdfi_pop(ctx, 1);
code = pdfi_newpath(ctx);
break;
- case K1('q'): /* gsave */
+ case TOKEN_q: /* gsave */
pdfi_pop(ctx, 1);
code = pdfi_op_q(ctx);
break;
- case K1('Q'): /* grestore */
+ case TOKEN_Q: /* grestore */
pdfi_pop(ctx, 1);
code = pdfi_op_Q(ctx);
break;
- case K1('r'): /* non-standard set rgb colour for non-stroke */
+ case TOKEN_r: /* non-standard set rgb colour for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setrgbfill_array(ctx);
break;
- case K2('r','e'): /* append rectangle */
+ case TOKEN_re: /* append rectangle */
pdfi_pop(ctx, 1);
code = pdfi_rectpath(ctx);
break;
- case K2('R','G'): /* set rgb colour for stroke */
+ case TOKEN_RG: /* set rgb colour for stroke */
pdfi_pop(ctx, 1);
code = pdfi_setrgbstroke(ctx);
break;
- case K2('r','g'): /* set rgb colour for non-stroke */
+ case TOKEN_rg: /* set rgb colour for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setrgbfill(ctx);
break;
- case K2('r','i'): /* set rendering intent */
+ case TOKEN_ri: /* set rendering intent */
pdfi_pop(ctx, 1);
code = pdfi_ri(ctx);
break;
- case K1('s'): /* closepath, stroke */
+ case TOKEN_s: /* closepath, stroke */
pdfi_pop(ctx, 1);
code = pdfi_closepath_stroke(ctx);
break;
- case K1('S'): /* stroke */
+ case TOKEN_S: /* stroke */
pdfi_pop(ctx, 1);
code = pdfi_stroke(ctx);
break;
- case K2('S','C'): /* set colour for stroke */
+ case TOKEN_SC: /* set colour for stroke */
pdfi_pop(ctx, 1);
code = pdfi_setstrokecolor(ctx);
break;
- case K2('s','c'): /* set colour for non-stroke */
+ case TOKEN_sc: /* set colour for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setfillcolor(ctx);
break;
- case K3('S','C','N'): /* set special colour for stroke */
+ case TOKEN_SCN: /* set special colour for stroke */
pdfi_pop(ctx, 1);
code = pdfi_setcolorN(ctx, stream_dict, page_dict, false);
break;
- case K3('s','c','n'): /* set special colour for non-stroke */
+ case TOKEN_scn: /* set special colour for non-stroke */
pdfi_pop(ctx, 1);
code = pdfi_setcolorN(ctx, stream_dict, page_dict, true);
break;
- case K2('s','h'): /* fill with sahding pattern */
+ case TOKEN_sh: /* fill with sahding pattern */
pdfi_pop(ctx, 1);
code = pdfi_shading(ctx, stream_dict, page_dict);
break;
- case K2('T','*'): /* Move to start of next text line */
+ case TOKEN_Tstar: /* Move to start of next text line */
pdfi_pop(ctx, 1);
code = pdfi_T_star(ctx);
break;
- case K2('T','c'): /* set character spacing */
+ case TOKEN_Tc: /* set character spacing */
pdfi_pop(ctx, 1);
code = pdfi_Tc(ctx);
break;
- case K2('T','d'): /* move text position */
+ case TOKEN_Td: /* move text position */
pdfi_pop(ctx, 1);
code = pdfi_Td(ctx);
break;
- case K2('T','D'): /* Move text position, set leading */
+ case TOKEN_TD: /* Move text position, set leading */
pdfi_pop(ctx, 1);
code = pdfi_TD(ctx);
break;
- case K2('T','f'): /* set font and size */
+ case TOKEN_Tf: /* set font and size */
pdfi_pop(ctx, 1);
code = pdfi_Tf(ctx, stream_dict, page_dict);
break;
- case K2('T','j'): /* show text */
+ case TOKEN_Tj: /* show text */
pdfi_pop(ctx, 1);
code = pdfi_Tj(ctx);
break;
- case K2('T','J'): /* show text with individual glyph positioning */
+ case TOKEN_TJ: /* show text with individual glyph positioning */
pdfi_pop(ctx, 1);
code = pdfi_TJ(ctx);
break;
- case K2('T','L'): /* set text leading */
+ case TOKEN_TL: /* set text leading */
pdfi_pop(ctx, 1);
code = pdfi_TL(ctx);
break;
- case K2('T','m'): /* set text matrix */
+ case TOKEN_Tm: /* set text matrix */
pdfi_pop(ctx, 1);
code = pdfi_Tm(ctx);
break;
- case K2('T','r'): /* set text rendering mode */
+ case TOKEN_Tr: /* set text rendering mode */
pdfi_pop(ctx, 1);
code = pdfi_Tr(ctx);
break;
- case K2('T','s'): /* set text rise */
+ case TOKEN_Ts: /* set text rise */
pdfi_pop(ctx, 1);
code = pdfi_Ts(ctx);
break;
- case K2('T','w'): /* set word spacing */
+ case TOKEN_Tw: /* set word spacing */
pdfi_pop(ctx, 1);
code = pdfi_Tw(ctx);
break;
- case K2('T','z'): /* set text matrix */
+ case TOKEN_Tz: /* set text matrix */
pdfi_pop(ctx, 1);
code = pdfi_Tz(ctx);
break;
- case K1('v'): /* append curve (initial point replicated) */
+ case TOKEN_v: /* append curve (initial point replicated) */
pdfi_pop(ctx, 1);
code = pdfi_v_curveto(ctx);
break;
- case K1('w'): /* setlinewidth */
+ case TOKEN_w: /* setlinewidth */
pdfi_pop(ctx, 1);
code = pdfi_setlinewidth(ctx);
break;
- case K1('W'): /* clip */
+ case TOKEN_W: /* clip */
pdfi_pop(ctx, 1);
ctx->clip_active = true;
ctx->do_eoclip = false;
break;
- case K2('W','*'): /* eoclip */
+ case TOKEN_Wstar: /* eoclip */
pdfi_pop(ctx, 1);
ctx->clip_active = true;
ctx->do_eoclip = true;
break;
- case K1('y'): /* append curve (final point replicated) */
+ case TOKEN_y: /* append curve (final point replicated) */
pdfi_pop(ctx, 1);
code = pdfi_y_curveto(ctx);
break;
- case K1('\''): /* move to next line and show text */
+ case TOKEN_APOSTROPHE: /* move to next line and show text */
pdfi_pop(ctx, 1);
code = pdfi_singlequote(ctx);
break;
- case K1('"'): /* set word and character spacing, move to next line, show text */
+ case TOKEN_QUOTE: /* set word and character spacing, move to next line, show text */
pdfi_pop(ctx, 1);
code = pdfi_doublequote(ctx);
break;
default:
- code = split_bogus_operator(ctx, source, stream_dict, page_dict);
- if (code < 0)
- return code;
- if (pdfi_count_stack(ctx) > 0) {
- keyword = (pdf_keyword *)ctx->stack_top[-1];
- if (keyword->key != TOKEN_NOT_A_KEYWORD)
- return REPAIRED_KEYWORD;
- }
+ /* Shouldn't we return an error here? Original code didn't seem to. */
break;
- }
+ }
+ /* We use a return value of 1 to indicate a repaired keyword (a pair of operators
+ * was concatenated, and we split them up). We must not return a value > 0 from here
+ * to avoid tripping that test.
+ */
+ if (code > 0)
+ code = 0;
+ return code;
+ } else if (((pdf_keyword *)keyword)->length > 3) {
+ if (ctx->args.pdfdebug) {
+ char Buffer[1024];
+ int length;
+
+ if (((pdf_keyword *)keyword)->length > 1023)
+ length = 1023;
+ else
+ length = ((pdf_keyword *)keyword)->length;
+
+ memcpy(Buffer, ((pdf_keyword *)keyword)->data, length);
+ Buffer[length] = 0x00;
+ dmprintf1(ctx->memory, " %s\n", Buffer);
+ }
+
+ /* This means we either have a corrupted or illegal operator. The most
+ * usual corruption is two concatented operators (eg QBT instead of Q BT)
+ * I plan to tackle this by trying to see if I can make two or more operators
+ * out of the mangled one. Note this will also be done below in the 'default'
+ * case where we don't recognise a keyword with 3 or fewer characters.
+ */
+ code = split_bogus_operator(ctx, source, stream_dict, page_dict);
+ if (code < 0)
+ return code;
+ if (pdfi_count_stack(ctx) > 0) {
+ keyword = ctx->stack_top[-1];
+ if (keyword != PDF_TOKEN_AS_OBJ(TOKEN_NOT_A_KEYWORD))
+ return REPAIRED_KEYWORD;
+ }
}
- /* We use a return value of 1 to indicate a repaired keyword (a pair of operators
- * was concatenated, and we split them up). We must not return a value > 0 from here
- * to avoid tripping that test.
- */
- if (code > 0)
- code = 0;
- return code;
+ return 0;
}
void local_save_stream_state(pdf_context *ctx, stream_save *local_save)
@@ -1699,10 +1821,9 @@ int pdfi_run_context(pdf_context *ctx, pdf_stream *stream_obj,
gs_color_space *PageDefaultRGB = ctx->page.DefaultRGB_cs;
gs_color_space *PageDefaultCMYK = ctx->page.DefaultCMYK_cs;
- /* increment their reference counts because we took a new reference to each */
- rc_increment(ctx->page.DefaultGray_cs);
- rc_increment(ctx->page.DefaultRGB_cs);
- rc_increment(ctx->page.DefaultCMYK_cs);
+ ctx->page.DefaultGray_cs = NULL;
+ ctx->page.DefaultRGB_cs = NULL;
+ ctx->page.DefaultCMYK_cs = NULL;
#if DEBUG_CONTEXT
dbgmprintf(ctx->memory, "pdfi_run_context BEGIN\n");
@@ -1714,6 +1835,20 @@ int pdfi_run_context(pdf_context *ctx, pdf_stream *stream_obj,
if (code < 0)
goto exit;
+ /* If no Default* space found, try using the Page level ones (if any) */
+ if (ctx->page.DefaultGray_cs == NULL) {
+ ctx->page.DefaultGray_cs = PageDefaultGray;
+ rc_increment(PageDefaultGray);
+ }
+ if (ctx->page.DefaultRGB_cs == NULL) {
+ ctx->page.DefaultRGB_cs = PageDefaultRGB;
+ rc_increment(PageDefaultRGB);
+ }
+ if (ctx->page.DefaultCMYK_cs == NULL) {
+ ctx->page.DefaultCMYK_cs = PageDefaultCMYK;
+ rc_increment(PageDefaultCMYK);
+ }
+
code = pdfi_copy_DefaultQState(ctx, &DefaultQState);
if (code < 0)
goto exit;
@@ -1743,6 +1878,7 @@ exit:
ctx->page.DefaultGray_cs = PageDefaultGray;
ctx->page.DefaultRGB_cs = PageDefaultRGB;
ctx->page.DefaultCMYK_cs = PageDefaultCMYK;
+
#if DEBUG_CONTEXT
dbgmprintf(ctx->memory, "pdfi_run_context END\n");
#endif
@@ -1900,6 +2036,7 @@ pdfi_interpret_content_stream(pdf_context *ctx, pdf_c_stream *content_stream,
pdf_c_stream *stream;
pdf_keyword *keyword;
pdf_stream *s = ctx->current_stream;
+ pdf_obj_type type;
/* 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
@@ -1908,9 +2045,18 @@ pdfi_interpret_content_stream(pdf_context *ctx, pdf_c_stream *content_stream,
* 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) {
+ while (s != NULL && pdfi_type_of(s) == PDF_STREAM) {
if (s->object_num > 0) {
if (s->object_num == stream_obj->object_num) {
+ pdf_dict *d = NULL;
+ bool known = false;
+
+ code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &d);
+ if (code >= 0) {
+ code = pdfi_dict_known(ctx, d, "Parent", &known);
+ if (code >= 0 && known)
+ (void)pdfi_dict_delete(ctx, d, "Parent");
+ }
pdfi_set_error(ctx, 0, NULL, E_PDF_CIRCULARREF, "pdfi_interpret_content_stream", "Aborting stream");
return_error(gs_error_circular_reference);
}
@@ -1952,11 +2098,12 @@ pdfi_interpret_content_stream(pdf_context *ctx, pdf_c_stream *content_stream,
break;
}
- if (ctx->stack_top[-1]->type == PDF_KEYWORD) {
repaired_keyword:
+ type = pdfi_type_of(ctx->stack_top[-1]);
+ if (type == PDF_FAST_KEYWORD) {
keyword = (pdf_keyword *)ctx->stack_top[-1];
- switch(keyword->key) {
+ switch((uintptr_t)keyword) {
case TOKEN_ENDSTREAM:
pdfi_pop(ctx,1);
goto exit;
@@ -1968,35 +2115,39 @@ repaired_keyword:
code = gs_note_error(gs_error_syntaxerror);
goto exit;
break;
- case TOKEN_NOT_A_KEYWORD:
- {
- pdf_dict *stream_dict = NULL;
-
- code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
- if (code < 0)
- goto exit;
-
- code = pdfi_interpret_stream_operator(ctx, stream, stream_dict, page_dict);
- if (code == REPAIRED_KEYWORD)
- goto repaired_keyword;
-
- if (code < 0) {
- pdfi_set_error(ctx, code, NULL, E_PDF_TOKENERROR, "pdf_interpret_content_stream", NULL);
- if (ctx->args.pdfstoponerror) {
- pdfi_clearstack(ctx);
- goto exit;
- }
- }
- }
- break;
case TOKEN_INVALID_KEY:
pdfi_set_error(ctx, 0, NULL, E_PDF_KEYWORDTOOLONG, "pdfi_interpret_content_stream", NULL);
pdfi_clearstack(ctx);
break;
- default:
+ case TOKEN_TOO_LONG:
pdfi_set_error(ctx, 0, NULL, E_PDF_MISSINGENDSTREAM, "pdfi_interpret_content_stream", NULL);
pdfi_clearstack(ctx);
break;
+ default:
+ goto execute;
+ }
+ }
+ else if (type == PDF_KEYWORD)
+ {
+execute:
+ {
+ pdf_dict *stream_dict = NULL;
+
+ code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
+ if (code < 0)
+ goto exit;
+
+ code = pdfi_interpret_stream_operator(ctx, stream, stream_dict, page_dict);
+ if (code == REPAIRED_KEYWORD)
+ goto repaired_keyword;
+
+ if (code < 0) {
+ pdfi_set_error(ctx, code, NULL, E_PDF_TOKENERROR, "pdf_interpret_content_stream", NULL);
+ if (ctx->args.pdfstoponerror) {
+ pdfi_clearstack(ctx);
+ goto exit;
+ }
+ }
}
}
if(stream->eof == true)
diff --git a/pdf/pdf_int.h b/pdf/pdf_int.h
index c841fc9f..4cf1dcb6 100644
--- a/pdf/pdf_int.h
+++ b/pdf/pdf_int.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
@@ -29,6 +29,9 @@ int pdfi_name_alloc(pdf_context *ctx, byte *key, uint32_t size, pdf_obj **o);
int pdfi_read_dict(pdf_context *ctx, pdf_c_stream *s, uint32_t indirect_num, uint32_t indirect_gen);
+int pdfi_read_bare_int(pdf_context *ctx, pdf_c_stream *s, int *parsed_int);
+int pdfi_read_bare_keyword(pdf_context *ctx, pdf_c_stream *s);
+
void local_save_stream_state(pdf_context *ctx, stream_save *local_save);
void local_restore_stream_state(pdf_context *ctx, stream_save *local_save);
void cleanup_context_interpretation(pdf_context *ctx, stream_save *local_save);
diff --git a/pdf/pdf_mark.c b/pdf/pdf_mark.c
index d625e34a..27b72d8c 100644
--- a/pdf/pdf_mark.c
+++ b/pdf/pdf_mark.c
@@ -50,7 +50,7 @@ static int pdfi_pdfmark_setparam_pair(pdf_context *ctx, pdf_name *Key, pdf_obj *
int code = 0;
/* Handle the Key */
- if (Key->type != PDF_NAME) {
+ if (pdfi_type_of(Key) != PDF_NAME) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -391,14 +391,20 @@ static int pdfi_pdfmark_add_Page_View(pdf_context *ctx, pdf_dict *link_dict, pdf
code = pdfi_array_get_no_store_R(ctx, dest_array, 0, (pdf_obj **)&page_dict);
if (code < 0) goto exit;
- if (page_dict->type != PDF_DICT) {
- code = gs_note_error(gs_error_typecheck);
- goto exit;
+ if(pdfi_type_of(page_dict) == PDF_INT) {
+ page_num = ((pdf_num *)page_dict)->value.i;
+ } else {
+ if (pdfi_type_of(page_dict) != PDF_DICT) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+
+ /* Find out which page number this is */
+ code = pdfi_page_get_number(ctx, page_dict, &page_num);
+ if (code < 0) goto exit;
}
- /* Find out which page number this is */
- code = pdfi_page_get_number(ctx, page_dict, &page_num);
- if (code < 0) goto exit;
+ page_num += ctx->Pdfmark_InitialPage;
/* Add /Page key to the link_dict
* Of course pdfwrite is numbering its pages starting at 1, because... of course :(
@@ -457,12 +463,12 @@ static int pdfi_pdfmark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
/* Note: in current implementation, PDF_STRING and PDF_NAME have all the same
* fields, but just in case that changes I treat them separately here.
*/
- if (name->type == PDF_STRING && dest->type == PDF_STRING) {
+ if (pdfi_type_of(name) == PDF_STRING && pdfi_type_of(dest) == PDF_STRING) {
if (!pdfi_string_cmp((pdf_string *)name, (pdf_string *)dest)) {
found = true;
break;
}
- } else if (name->type == PDF_NAME && dest->type == PDF_NAME) {
+ } else if (pdfi_type_of(name) == PDF_NAME && pdfi_type_of(dest) == PDF_NAME) {
if (!pdfi_name_cmp((pdf_name *)name, (pdf_name *)dest)) {
found = true;
break;
@@ -482,18 +488,19 @@ static int pdfi_pdfmark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
code = pdfi_array_get(ctx, Names, i+1, (pdf_obj **)&D_dict);
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) {
+ switch (pdfi_type_of(D_dict)) {
+ case 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;
+ break;
+ case PDF_ARRAY:
dest_array = (pdf_array *)D_dict;
D_dict = NULL;
- } else {
+ break;
+ default:
code = gs_note_error(gs_error_typecheck);
goto exit;
- }
}
/* Process the dest_array to replace with /Page /View */
@@ -512,7 +519,7 @@ static int pdfi_pdfmark_handle_dest_names(pdf_context *ctx, pdf_dict *link_dict,
*/
int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
{
- int code = 0;
+ int code = 0, code1 = 0;
pdf_dict *Dests = NULL;
pdf_obj *Dest = NULL;
bool delete_Dest = true;
@@ -529,14 +536,13 @@ int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
code = pdfi_dict_knownget_type(ctx, ctx->Root, "Names", PDF_DICT, (pdf_obj **)&Names_dict);
if (code < 0) goto exit;
- switch (Dest->type) {
+ switch (pdfi_type_of(Dest)) {
case PDF_ARRAY:
code = pdfi_pdfmark_add_Page_View(ctx, link_dict, (pdf_array *)Dest);
if (code < 0) goto exit;
break;
case PDF_NAME:
- case PDF_STRING:
- if (Dest->type == PDF_NAME && Dests != NULL) {
+ if (Dests != NULL) {
/* Case where it's a name to look up in Contents(Root) /Dests */
code = pdfi_dict_get_by_key(ctx, Dests, (const pdf_name *)Dest, (pdf_obj **)&dest_array);
if (code == gs_error_undefined) {
@@ -545,13 +551,17 @@ int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
goto exit;
}
if (code < 0) goto exit;
- if (dest_array->type != PDF_ARRAY) {
+ if (pdfi_type_of(dest_array) != PDF_ARRAY) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
code = pdfi_pdfmark_add_Page_View(ctx, link_dict, dest_array);
if (code < 0) goto exit;
- } else if (Names_dict != NULL) {
+ break;
+ }
+ /* fallthrough */
+ case PDF_STRING:
+ if (Names_dict != NULL) {
/* Looking in Catalog(Root) for /Names<</Dests<</Names [name dict array]>>>> */
code = pdfi_dict_knownget_type(ctx, Names_dict, "Dests", PDF_DICT, (pdf_obj **)&Dests);
if (code < 0) goto exit;
@@ -580,8 +590,9 @@ int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
exit:
if (delete_Dest) {
/* Delete the Dest key */
- code = pdfi_dict_delete(ctx, link_dict, "Dest");
- if (code < 0) goto exit;
+ code1 = pdfi_dict_delete(ctx, link_dict, "Dest");
+ if (code1 < 0 && code >= 0)
+ code = code1;
}
pdfi_countdown(Dest);
pdfi_countdown(Dests);
@@ -591,6 +602,233 @@ int pdfi_pdfmark_modDest(pdf_context *ctx, pdf_dict *link_dict)
return code;
}
+static int pdfi_check_limits(pdf_context *ctx, pdf_dict *node, char *str, int len)
+{
+ int code = 0, min, i, len2 = 0;
+ pdf_array *Limits = NULL;
+ pdf_string *Str = NULL;
+ char *str2 = NULL;
+
+ code = pdfi_dict_get_type(ctx, node, "Limits", PDF_ARRAY, (pdf_obj **)&Limits);
+ if (code < 0)
+ goto error;
+
+ if (pdfi_array_size(Limits) != 2) {
+ /* Limits are not valid, just ignore them. The calling code will then check
+ * the Names array.
+ */
+ pdfi_set_warning(ctx, 0, NULL, PDF_W_BAD_TREE_LIMITS, "pdfi_get_name_from_node", 0);
+ goto error;
+ }
+
+ code = pdfi_array_get_type(ctx, Limits, 0, PDF_STRING, (pdf_obj **)&Str);
+ if (code < 0)
+ goto error;
+
+ if (pdfi_type_of(Str) == PDF_NAME) {
+ code = pdfi_string_from_name(ctx, (pdf_name *)Str, &str2, &len2);
+ if (code < 0)
+ return code;
+ } else {
+ len2 = ((pdf_string *)Str)->length;
+ str2 = (char *)gs_alloc_bytes(ctx->memory, len2 + 1, "pdfi_get_named_dest");
+ if (str2 == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ memcpy(str2, ((pdf_string *)Str)->data, len2);
+ str2[len2] = 0;
+ }
+
+ pdfi_countdown(Str);
+ Str = NULL;
+
+ min = len;
+ if (len2 < min)
+ min = len2;
+
+ for (i=0;i< min;i++) {
+ if (str[i] < str2[i]) {
+ code = gs_note_error(gs_error_undefined);
+ goto error;
+ }
+ if (str[i] != str2[i])
+ break;
+ }
+ if (i > min && len2 < Str->length) {
+ code = gs_note_error(gs_error_undefined);
+ goto error;
+ }
+ gs_free_object(ctx->memory, str2, "pdfi_get_named_dest");
+ str2 = NULL;
+
+ code = pdfi_array_get_type(ctx, Limits, 1, PDF_STRING, (pdf_obj **)&Str);
+ if (code < 0)
+ goto error;
+
+ if (pdfi_type_of(Str) == PDF_NAME) {
+ code = pdfi_string_from_name(ctx, (pdf_name *)Str, &str2, &len2);
+ if (code < 0)
+ return code;
+ } else {
+ len2 = ((pdf_string *)Str)->length;
+ str2 = (char *)gs_alloc_bytes(ctx->memory, len2 + 1, "pdfi_get_named_dest");
+ if (str2 == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ memcpy(str2, ((pdf_string *)Str)->data, len2);
+ str2[len2] = 0;
+ }
+
+ pdfi_countdown(Str);
+ Str = NULL;
+
+ min = len;
+ if (len2 < min)
+ min = len2;
+
+ for (i=0;i< min;i++) {
+ if (str[i] > str2[i]) {
+ code = gs_note_error(gs_error_undefined);
+ goto error;
+ }
+ if (str[i] != str2[i])
+ break;
+ }
+
+ if (i > min && len > len2)
+ code = gs_note_error(gs_error_undefined);
+
+error:
+ gs_free_object(ctx->memory, str2, "pdfi_get_named_dest");
+ pdfi_countdown(Str);
+ pdfi_countdown(Limits);
+ return code;
+}
+
+static int pdfi_get_name_from_node(pdf_context *ctx, pdf_dict *node, char *str, pdf_obj **Name)
+{
+ int i = 0, len = strlen(str), code = 0;
+ pdf_string *StrKey = NULL;
+ pdf_array *NamesArray = NULL;
+ pdf_dict *Kid = NULL;
+ bool known;
+
+ code = pdfi_dict_known(ctx, node, "Names", &known);
+ if (code < 0)
+ goto error;
+
+ if (known) {
+ code = pdfi_dict_known(ctx, node, "Limits", &known);
+ if (code < 0)
+ goto error;
+
+ if (!known) {
+ /* No Limits array (a required entry), so just assume that the
+ * string is in this node and check all the Names anyway
+ */
+ pdfi_set_warning(ctx, 0, NULL, PDF_W_NO_TREE_LIMITS, "pdfi_get_name_from_node", 0);
+ } else {
+ code = pdfi_check_limits(ctx, node, str, len);
+ if (code < 0)
+ goto error;
+ }
+
+ code = pdfi_dict_get_type(ctx, node, "Names", PDF_ARRAY, (pdf_obj **)&NamesArray);
+ if (code < 0)
+ goto error;
+
+ if (pdfi_array_size(NamesArray) & 1)
+ pdfi_set_warning(ctx, 0, NULL, PDF_W_NAMES_ARRAY_SIZE, "pdfi_get_name_from_node", 0);
+
+ for (i = 0;i < pdfi_array_size(NamesArray) / 2; i++) {
+ code = pdfi_array_get_type(ctx, NamesArray, i * 2, PDF_STRING, (pdf_obj **)&StrKey);
+ if (code < 0)
+ goto error;
+
+ if (StrKey->length == len && strncmp((const char *)StrKey->data, str, len) == 0) {
+ code = pdfi_array_get(ctx, NamesArray, (i * 2) + 1, (pdf_obj **)Name);
+ goto error;
+ }
+ pdfi_countdown(StrKey);
+ StrKey = NULL;
+ }
+ pdfi_countdown(NamesArray);
+ NamesArray = NULL;
+ }
+
+ /* Either no Names array (initial node) or not in array */
+ code = pdfi_dict_get_type(ctx, node, "Kids", PDF_ARRAY, (pdf_obj **)&NamesArray);
+ if (code < 0)
+ goto error;
+
+ for (i = 0;i < pdfi_array_size(NamesArray); i++) {
+ code = pdfi_array_get_type(ctx, NamesArray, i, PDF_DICT, (pdf_obj **)&Kid);
+ if (code < 0)
+ goto error;
+
+ code = pdfi_get_name_from_node(ctx, Kid, str, Name);
+ pdfi_countdown(Kid);
+ Kid = NULL;
+ if (code == 0)
+ break;
+
+ if (code < 0) {
+ if (code == gs_error_undefined)
+ continue;
+ goto error;
+ }
+ }
+
+error:
+ pdfi_countdown(Kid);
+ pdfi_countdown(StrKey);
+ pdfi_countdown(NamesArray);
+ return code;
+}
+
+static int pdfi_get_named_dest(pdf_context *ctx, pdf_obj *Named, pdf_obj **Dest)
+{
+ int code = 0, len = 0;
+ pdf_dict *Names = NULL, *Dests = NULL;
+ char *str = NULL;
+
+ code = pdfi_dict_get_type(ctx, ctx->Root, "Names", PDF_DICT, (pdf_obj **)&Names);
+ if (code < 0)
+ goto error;
+
+ code = pdfi_dict_get_type(ctx, Names, "Dests", PDF_DICT, (pdf_obj **)&Dests);
+ if (code < 0)
+ goto error;
+
+ if (pdfi_type_of(Named) == PDF_NAME) {
+ code = pdfi_string_from_name(ctx, (pdf_name *)Named, &str, &len);
+ if (code < 0)
+ return code;
+ } else {
+ len = ((pdf_string *)Named)->length;
+ str = (char *)gs_alloc_bytes(ctx->memory, len + 1, "pdfi_get_named_dest");
+ if (str == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error;
+ }
+ memcpy(str, ((pdf_string *)Named)->data, len);
+ str[len] = 0;
+ }
+
+ code = pdfi_get_name_from_node(ctx, Dests, str, Dest);
+
+error:
+ if (pdfi_type_of(Named) == PDF_NAME)
+ (void)pdfi_free_string_from_name(ctx, str);
+ else
+ gs_free_object(ctx->memory, str, "pdfi_get_named_dest");
+ pdfi_countdown(Names);
+ pdfi_countdown(Dests);
+ return code;
+}
+
/* Special handling for "A" in Link annotations and Outlines
* Will delete A if handled and if A_key is provided.
*/
@@ -607,7 +845,7 @@ int pdfi_pdfmark_modA(pdf_context *ctx, pdf_dict *dict)
code = pdfi_dict_get_no_store_R(ctx, dict, "A", (pdf_obj **)&A_dict);
if (code < 0) goto exit;
- if (A_dict->type != PDF_DICT) {
+ if (pdfi_type_of(A_dict) != PDF_DICT) {
/* Invalid AP, just delete it because I dunno what to do...
* TODO: Should flag a warning here
*/
@@ -631,19 +869,33 @@ int pdfi_pdfmark_modA(pdf_context *ctx, pdf_dict *dict)
if (code <= 0) goto exit;
/* We only handle GoTo for now */
if (pdfi_name_is(S_name, "GoTo")) {
- code = pdfi_dict_knownget_type(ctx, A_dict, "D", PDF_ARRAY, (pdf_obj **)&D_array);
- if (code == 0) goto exit;
- if (code < 0) {
- if (code == gs_error_typecheck) {
- /* TODO: Are there other cases to handle?
- * Sample tests_private/pdf/sumatra/recursive_action_destinations.pdf
- * has a recursive destination that has an indirect ref here. We return a
- * typecheck and that causes us to omit the whole thing, but is that
- * really the best treatment?
- */
+ code = pdfi_dict_knownget(ctx, A_dict, "D", (pdf_obj **)&D_array);
+ if (code <= 0)
+ goto exit;
+ if (pdfi_type_of(D_array) == PDF_STRING || pdfi_type_of(D_array) == PDF_NAME)
+ {
+ pdf_obj *Dest = NULL;
+
+ code = pdfi_get_named_dest(ctx, (pdf_obj *)D_array, &Dest);
+ if (code < 0)
+ goto exit;
+ pdfi_countdown(D_array);
+ D_array = NULL;
+ if (pdfi_type_of(Dest) != PDF_DICT) {
+ pdfi_countdown(Dest);
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
}
+ code = pdfi_dict_knownget(ctx, (pdf_dict *)Dest, "D", (pdf_obj **)&D_array);
+ pdfi_countdown(Dest);
+ if (code <= 0)
+ goto exit;
+ }
+ if (pdfi_type_of(D_array) != PDF_ARRAY) {
+ code = gs_note_error(gs_error_typecheck);
goto exit;
}
+
/* Process the D array to replace with /Page /View */
code = pdfi_pdfmark_add_Page_View(ctx, dict, D_array);
if (code < 0) goto exit;
@@ -1043,7 +1295,7 @@ void pdfi_pdfmark_write_boxes(pdf_context *ctx, pdf_dict *page_dict)
pdf_array *new_array = NULL;
/* Box is present in page dicitonayr, check it's an array */
- if (o->type != PDF_ARRAY) {
+ if (pdfi_type_of(o) != PDF_ARRAY) {
pdfi_countdown(o);
continue;
}
diff --git a/pdf/pdf_misc.c b/pdf/pdf_misc.c
index 11c5dde5..e027baec 100644
--- a/pdf/pdf_misc.c
+++ b/pdf/pdf_misc.c
@@ -149,7 +149,7 @@ int pdfi_setrenderingintent(pdf_context *ctx, pdf_name *n)
int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len)
{
- if (n->type != PDF_NAME)
+ if (pdfi_type_of(n) != PDF_NAME)
return gs_note_error(gs_error_typecheck);
*str = NULL;
@@ -166,6 +166,13 @@ int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len)
return 0;
}
+int pdfi_free_string_from_name(pdf_context *ctx, char *str)
+{
+ if (str != NULL)
+ gs_free_object(ctx->memory, str, "pdfi_free_string_from_name");
+ return 0;
+}
+
void normalize_rectangle(double *d)
{
double d1[4];
diff --git a/pdf/pdf_misc.h b/pdf/pdf_misc.h
index 8642b088..a879ec2b 100644
--- a/pdf/pdf_misc.h
+++ b/pdf/pdf_misc.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
@@ -23,6 +23,7 @@ bool pdfi_name_is(const pdf_name *n, const char *s);
int pdfi_name_cmp(const pdf_name *n1, const pdf_name *n2);
int pdfi_string_cmp(const pdf_string *n1, const pdf_string *n2);
int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len);
+int pdfi_free_string_from_name(pdf_context *ctx, char *str);
gs_color_space_index pdfi_get_color_space_index(pdf_context *ctx, const gs_color_space *pcs);
gs_color_space_index pdfi_currentcolorspace(pdf_context *ctx, int index);
diff --git a/pdf/pdf_obj.c b/pdf/pdf_obj.c
index 58bd59b0..aae9401b 100644
--- a/pdf/pdf_obj.c
+++ b/pdf/pdf_obj.c
@@ -36,12 +36,12 @@
int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pdf_obj **obj)
{
int bytes = 0;
+ int code = 0;
switch(type) {
case PDF_ARRAY_MARK:
case PDF_DICT_MARK:
case PDF_PROC_MARK:
- case PDF_NULL:
bytes = sizeof(pdf_obj);
break;
case PDF_INT:
@@ -50,7 +50,10 @@ 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) + size - sizeof(PDF_NAME_DECLARED_LENGTH);
+ bytes = sizeof(pdf_string) + size - PDF_NAME_DECLARED_LENGTH;
+ break;
+ case PDF_BUFFER:
+ bytes = sizeof(pdf_buffer);
break;
case PDF_ARRAY:
bytes = sizeof(pdf_array);
@@ -61,11 +64,8 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
case PDF_INDIRECT:
bytes = sizeof(pdf_indirect_ref);
break;
- case PDF_BOOL:
- bytes = sizeof(pdf_bool);
- break;
case PDF_KEYWORD:
- bytes = sizeof(pdf_keyword) + size - sizeof(PDF_NAME_DECLARED_LENGTH);
+ bytes = sizeof(pdf_keyword) + size - 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.
@@ -76,23 +76,34 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
case PDF_STREAM:
bytes = sizeof(pdf_stream);
break;
+ case PDF_NULL:
+ case PDF_BOOL:
default:
- return_error(gs_error_typecheck);
+ code = gs_note_error(gs_error_typecheck);
+ goto error_out;
}
*obj = (pdf_obj *)gs_alloc_bytes(ctx->memory, bytes, "pdfi_object_alloc");
- if (*obj == NULL)
- return_error(gs_error_VMerror);
+ if (*obj == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error_out;
+ }
memset(*obj, 0x00, bytes);
(*obj)->ctx = ctx;
(*obj)->type = type;
switch(type) {
+/* PDF_NULL and PDF_BOOL are now handled as special (not allocated) data types
+ and we will return an error in the switch above if we get a call to allocate
+ one of these. Having the cases isn't harmful but Coverity complains of dead
+ code, so commenting these out to silence Coverity while preserving the old
+ semantics to indicate what's happening.
case PDF_NULL:
+ case PDF_BOOL: */
+
case PDF_INT:
case PDF_REAL:
case PDF_INDIRECT:
- case PDF_BOOL:
case PDF_ARRAY_MARK:
case PDF_DICT_MARK:
case PDF_PROC_MARK:
@@ -102,6 +113,24 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
case PDF_NAME:
((pdf_string *)*obj)->length = size;
break;
+ case PDF_BUFFER:
+ {
+ pdf_buffer *b = (pdf_buffer *)*obj;
+ /* NOTE: size can be 0 if the caller wants to allocate the data area itself
+ */
+ if (size > 0) {
+ b->data = gs_alloc_bytes(ctx->memory, size, "pdfi_object_alloc");
+ if (b->data == NULL) {
+ code = gs_note_error(gs_error_VMerror);
+ goto error_out;
+ }
+ }
+ else {
+ b->data = NULL;
+ }
+ b->length = size;
+ }
+ break;
case PDF_ARRAY:
{
pdf_obj **values = NULL;
@@ -110,10 +139,8 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
if (size > 0) {
values = (pdf_obj **)gs_alloc_bytes(ctx->memory, size * sizeof(pdf_obj *), "pdfi_object_alloc");
if (values == NULL) {
- gs_free_object(ctx->memory, *obj, "pdfi_object_alloc");
- gs_free_object(ctx->memory, values, "pdfi_object_alloc");
- *obj = NULL;
- return_error(gs_error_VMerror);
+ code = gs_note_error(gs_error_VMerror);
+ goto error_out;
}
((pdf_array *)*obj)->values = values;
memset(((pdf_array *)*obj)->values, 0x00, size * sizeof(pdf_obj *));
@@ -128,9 +155,8 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
if (size > 0) {
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");
- *obj = NULL;
- return_error(gs_error_VMerror);
+ code = gs_note_error(gs_error_VMerror);
+ goto error_out;
}
((pdf_dict *)*obj)->list = entries;
memset(((pdf_dict *)*obj)->list, 0x00, size * sizeof(pdf_dict_entry));
@@ -150,6 +176,10 @@ int pdfi_object_alloc(pdf_context *ctx, pdf_obj_type type, unsigned int size, pd
dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", (*obj)->type, (*obj)->UID);
#endif
return 0;
+error_out:
+ gs_free_object(ctx->memory, *obj, "pdfi_object_alloc");
+ *obj = NULL;
+ return code;
}
/* Create a PDF number object from a numeric value. Attempts to create
@@ -217,25 +247,36 @@ static void pdfi_free_stream(pdf_obj *o)
gs_free_object(OBJ_MEMORY(o), o, "pdfi_free_stream");
}
+static void pdfi_free_buffer(pdf_obj *o)
+{
+ pdf_buffer *b = (pdf_buffer *)o;
+
+ gs_free_object(OBJ_MEMORY(b), b->data, "pdfi_free_buffer(data)");
+ gs_free_object(OBJ_MEMORY(o), o, "pdfi_free_buffer");
+}
+
void pdfi_free_object(pdf_obj *o)
{
if (o == NULL)
return;
+ if ((intptr_t)o < (intptr_t)TOKEN__LAST_KEY)
+ return;
switch(o->type) {
case PDF_ARRAY_MARK:
case PDF_DICT_MARK:
case PDF_PROC_MARK:
- case PDF_NULL:
case PDF_INT:
case PDF_REAL:
case PDF_INDIRECT:
- case PDF_BOOL:
gs_free_object(OBJ_MEMORY(o), o, "pdf interpreter object refcount to 0");
break;
case PDF_STRING:
case PDF_NAME:
pdfi_free_namestring(o);
break;
+ case PDF_BUFFER:
+ pdfi_free_buffer(o);
+ break;
case PDF_ARRAY:
pdfi_free_array(o);
break;
@@ -257,8 +298,12 @@ void pdfi_free_object(pdf_obj *o)
case PDF_CMAP:
pdfi_free_cmap(o);
break;
+ case PDF_BOOL:
+ case PDF_NULL:
+ dbgmprintf(OBJ_MEMORY(o), "!!! Attempting to free non-allocated object type !!!\n");
+ break;
default:
- dbgmprintf(OBJ_MEMORY(o), "!!! Attempting to free unknown obect type !!!\n");
+ dbgmprintf(OBJ_MEMORY(o), "!!! Attempting to free unknown object type !!!\n");
break;
}
}
@@ -274,7 +319,7 @@ int pdfi_obj_dict_to_stream(pdf_context *ctx, pdf_dict *dict, pdf_stream **strea
int code = 0;
pdf_stream *new_stream = NULL;
- if (dict->type != PDF_DICT)
+ if (pdfi_type_of(dict) != PDF_DICT)
return_error(gs_error_typecheck);
code = pdfi_object_alloc(ctx, PDF_STREAM, 0, (pdf_obj **)&new_stream);
@@ -445,7 +490,7 @@ int pdfi_obj_get_label(pdf_context *ctx, pdf_obj *obj, char **label)
goto exit;
}
- if (obj->type == PDF_INDIRECT)
+ if (pdfi_type_of(obj) == PDF_INDIRECT)
snprintf(string, length, template, ref->ref_object_num, ref->ref_generation_num);
else
snprintf(string, length, template, obj->object_num, obj->generation_num);
@@ -566,10 +611,10 @@ static int pdfi_obj_indirect_str(pdf_context *ctx, pdf_obj *obj, byte **data, in
if (code < 0 && code != gs_error_circular_reference)
goto exit;
if (code == 0) {
- if (object->type == PDF_STREAM) {
+ if (pdfi_type_of(object) == PDF_STREAM) {
code = pdfi_pdfmark_stream(ctx, (pdf_stream *)object);
if (code < 0) goto exit;
- } else if (object->type == PDF_DICT) {
+ } else if (pdfi_type_of(object) == PDF_DICT) {
code = pdfi_pdfmark_dict(ctx, (pdf_dict *)object);
if (code < 0) goto exit;
} else {
@@ -596,13 +641,12 @@ static int pdfi_obj_bool_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *l
{
int code = 0;
int size = 5;
- pdf_bool *bool = (pdf_bool *)obj;
char *buf;
buf = (char *)gs_alloc_bytes(ctx->memory, size, "pdfi_obj_bool_str(data)");
if (buf == NULL)
return_error(gs_error_VMerror);
- if (bool->value) {
+ if (obj == PDF_TRUE_OBJ) {
memcpy(buf, (byte *)"true", 4);
*len = 4;
} else {
@@ -665,6 +709,8 @@ static int pdfi_obj_string_str(pdf_context *ctx, pdf_obj *obj, byte **data, int
* can have special characters. So I will handle the minimum that seems needed for that.
*/
switch (*ptr) {
+ case 0x0a:
+ case 0x0d:
case '(':
case ')':
case '\\':
@@ -694,6 +740,16 @@ static int pdfi_obj_string_str(pdf_context *ctx, pdf_obj *obj, byte **data, int
bufptr = buf + 1;
for (i=0,ptr=string->data;i<string_len;i++) {
switch (*ptr) {
+ case 0x0d:
+ *bufptr++ = '\\';
+ *bufptr++ = 'r';
+ ptr++;
+ continue;
+ case 0x0a:
+ *bufptr++ = '\\';
+ *bufptr++ = 'n';
+ ptr++;
+ continue;
case '(':
case ')':
case '\\':
@@ -920,6 +976,28 @@ static int pdfi_obj_dict_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *l
return code;
}
+#define PARAM1(A) # A,
+#define PARAM2(A,B) A,
+static const char pdf_token_strings[][10] = {
+#include "pdf_tokens.h"
+};
+
+static int pdfi_obj_fast_keyword_str(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
+{
+ int code = 0;
+ const char *s = pdf_token_strings[(uintptr_t)obj];
+ int size = (int)strlen(s) + 1;
+ byte *buf;
+
+ buf = gs_alloc_bytes(ctx->memory, size, "pdfi_obj_name_str(data)");
+ if (buf == NULL)
+ return_error(gs_error_VMerror);
+ memcpy(buf, s, size);
+ *data = buf;
+ *len = size;
+ return code;
+}
+
obj_str_dispatch_t obj_str_dispatch[] = {
{PDF_NAME, pdfi_obj_name_str},
{PDF_ARRAY, pdfi_obj_array_str},
@@ -931,6 +1009,7 @@ obj_str_dispatch_t obj_str_dispatch[] = {
{PDF_STREAM, pdfi_obj_stream_str},
{PDF_INDIRECT, pdfi_obj_indirect_str},
{PDF_NULL, pdfi_obj_null_str},
+ {PDF_FAST_KEYWORD, pdfi_obj_fast_keyword_str},
{0, NULL}
};
@@ -940,11 +1019,13 @@ int pdfi_obj_to_string(pdf_context *ctx, pdf_obj *obj, byte **data, int *len)
{
obj_str_dispatch_t *dispatch_ptr;
int code = 0;
+ pdf_obj_type type;
*data = NULL;
*len = 0;
+ type = pdfi_type_of(obj);
for (dispatch_ptr = obj_str_dispatch; dispatch_ptr->func; dispatch_ptr ++) {
- if (obj->type == dispatch_ptr->type) {
+ if (type == dispatch_ptr->type) {
code = dispatch_ptr->func(ctx, obj, data, len);
goto exit;
}
diff --git a/pdf/pdf_obj.h b/pdf/pdf_obj.h
index 99c9a178..eb512db9 100644
--- a/pdf/pdf_obj.h
+++ b/pdf/pdf_obj.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
@@ -25,4 +25,90 @@ int pdfi_obj_charstr_to_name(pdf_context *ctx, const char *charstr, pdf_name **n
int pdfi_obj_get_label(pdf_context *ctx, pdf_obj *obj, char **label);
int pdfi_num_alloc(pdf_context *ctx, double d, pdf_num **num);
+static inline int
+pdfi_obj_to_real(pdf_context *ctx, pdf_obj *obj, double *d)
+{
+ pdf_num *num = (pdf_num *)obj;
+
+ switch (pdfi_type_of(num)) {
+ case PDF_INT:
+ *d = (double)num->value.i;
+ break;
+ case PDF_REAL:
+ *d = num->value.d;
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
+
+ return 0;
+}
+
+static inline int
+pdfi_obj_to_float(pdf_context *ctx, pdf_obj *obj, float *f)
+{
+ pdf_num *num = (pdf_num *)obj;
+
+ switch (pdfi_type_of(num)) {
+ case PDF_INT:
+ *f = (float)num->value.i;
+ break;
+ case PDF_REAL:
+ *f = (float)num->value.d;
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
+
+ return 0;
+}
+
+static inline int
+pdfi_obj_to_int(pdf_context *ctx, pdf_obj *obj, int64_t *i)
+{
+ pdf_num *num = (pdf_num *)obj;
+ int64_t tmp;
+
+ switch (pdfi_type_of(num)) {
+ case PDF_INT:
+ *i = num->value.i;
+ break;
+ case PDF_REAL:
+ /* We shouldn't be given a real here. We will grudgingly accept
+ * (with a warning) an int given as a real, but will error out
+ * otherwise. If we find a case where we need to accept reals
+ * as ints, we'll do a new version of this function called something
+ * like pdfi_obj_real_as_int what will just cast it down. */
+ tmp = (int64_t)num->value.d;
+ if ((double)tmp != num->value.d) {
+ return_error(gs_error_typecheck);
+ }
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_INT_AS_REAL, "pdfi_obj_to_int", NULL);
+ *i = tmp;
+ break;
+ default:
+ return_error(gs_error_typecheck);
+ }
+
+ return 0;
+}
+
+/* NOTE: the buffer object takes ownership of "data" */
+static inline int
+pdfi_buffer_set_data(pdf_obj *o, byte *data, int32_t length)
+{
+ pdf_buffer *b = (pdf_buffer *)o;
+ if (pdfi_type_of(b) != PDF_BUFFER) {
+ return_error(gs_error_typecheck);
+ }
+
+ if (b->data) {
+ gs_free_object(OBJ_MEMORY(b), b->data, "pdfi_buffer_set_data(data)");
+ }
+ b->data = data;
+ b->length = length;
+ return 0;
+}
+
+
#endif
diff --git a/pdf/pdf_optcontent.c b/pdf/pdf_optcontent.c
index 484d72c9..288ee231 100644
--- a/pdf/pdf_optcontent.c
+++ b/pdf/pdf_optcontent.c
@@ -167,8 +167,8 @@ pdfi_oc_check_OCMD_array(pdf_context *ctx, pdf_array *array, ocmd_p_type type)
code = pdfi_array_get(ctx, array, i, &val);
if (code < 0) continue;
- if (val->type != PDF_DICT) {
- dmprintf1(ctx->memory, "WARNING: OCMD array contains item type %d, expected PDF_DICT or PDF_NULL\n", val->type);
+ if (pdfi_type_of(val) != PDF_DICT) {
+ dmprintf1(ctx->memory, "WARNING: OCMD array contains item type %d, expected PDF_DICT or PDF_NULL\n", pdfi_type_of(val));
pdfi_countdown(val);
val = NULL;
continue;
@@ -235,9 +235,9 @@ pdfi_oc_check_OCMD(pdf_context *ctx, pdf_dict *ocdict)
code = pdfi_dict_knownget(ctx, ocdict, "OCGs", &obj);
if (code <= 0)
goto cleanup;
- if (obj->type == PDF_ARRAY) {
+ if (pdfi_type_of(obj) == PDF_ARRAY) {
OCGs_array = (pdf_array *)obj;
- } else if (obj->type == PDF_DICT) {
+ } else if (pdfi_type_of(obj) == PDF_DICT) {
OCGs_dict = (pdf_dict *)obj;
} else {
goto cleanup;
@@ -367,7 +367,7 @@ static int pdfi_oc_levels_set(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64
byte *new = NULL;
uint64_t newmax;
- if (index > levels->max_flags) {
+ if (index > levels->max_flags - 1) {
/* Expand the flags buffer */
newmax = levels->max_flags + NUM_CONTENT_LEVELS;
if (index > newmax)
@@ -390,7 +390,7 @@ static int pdfi_oc_levels_set(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64
static int pdfi_oc_levels_clear(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64_t index)
{
- if (index > levels->max_flags)
+ if (index > levels->max_flags - 1)
return -1;
if (levels->flags[index] != 0)
levels->num_off --;
@@ -446,16 +446,19 @@ int pdfi_op_MP(pdf_context *ctx)
goto exit;
o = ctx->stack_top[-1];
- if (o->type != PDF_NAME) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
+ pdfi_countup(o);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(o) != PDF_NAME) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
}
code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "MP");
ctx->BMClevel ++;
exit:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(o);
return code;
}
@@ -463,17 +466,20 @@ 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;
+ pdf_obj **objarray = NULL, *o = 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)
+ if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) {
+ pdfi_pop(ctx, 2); /* pop args */
goto exit;
+ }
- if ((ctx->stack_top[-2])->type != PDF_NAME) {
+ if (pdfi_type_of(ctx->stack_top[-2]) != PDF_NAME) {
+ pdfi_pop(ctx, 2); /* pop args */
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -485,30 +491,38 @@ int pdfi_op_DP(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
}
objarray[0] = ctx->stack_top[-2];
+ pdfi_countup(objarray[0]);
+ o = ctx->stack_top[-2];
+ pdfi_countup(o);
+ pdfi_pop(ctx, 2); /* pop args */
- 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) {
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)o, stream_dict, page_dict, (pdf_obj **)&properties);
+ if(code < 0)
+ goto exit;
+ if (pdfi_type_of(properties) != PDF_DICT) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ objarray[1] = (pdf_obj *)properties;
+ break;
+ case PDF_DICT:
+ objarray[1] = o;
+ break;
+ default:
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)
+ if (objarray != NULL) {
+ pdfi_countdown(objarray[0]);
gs_free_object(ctx->memory, objarray, "free pdfi_op_DP");
- pdfi_pop(ctx, 2); /* pop args */
+ }
+ pdfi_countdown(o);
pdfi_countdown(properties);
return code;
}
@@ -525,13 +539,18 @@ int pdfi_op_BMC(pdf_context *ctx)
if (pdfi_count_stack(ctx) < 1)
return_error(gs_error_stackunderflow);
- if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent)
+ if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) {
+ pdfi_pop(ctx, 1);
goto exit;
+ }
o = ctx->stack_top[-1];
- if (o->type != PDF_NAME) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
+ pdfi_countup(o);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(o) != PDF_NAME) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
}
ctx->BDCWasOC = false;
@@ -539,7 +558,7 @@ int pdfi_op_BMC(pdf_context *ctx)
ctx->BMClevel ++;
exit:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(o);
return code;
}
@@ -551,7 +570,7 @@ 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;
+ pdf_obj **objarray = NULL, *o = NULL;;
/* This will also prevent us writing out an EMC if the BDC is in any way invalid */
ctx->BDCWasOC = true;
@@ -564,7 +583,12 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
ctx->BMClevel ++;
tag = (pdf_name *)ctx->stack_top[-2];
- if (tag->type != PDF_NAME)
+ pdfi_countup(tag);
+ o = ctx->stack_top[-1];
+ pdfi_countup(o);
+ pdfi_pop(ctx, 2);
+
+ if (pdfi_type_of(tag) != PDF_NAME)
goto exit;
if (!pdfi_name_is(tag, "OC")) {
@@ -578,23 +602,25 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
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) {
+ objarray[0] = (pdf_obj *)tag;
+
+ switch (pdfi_type_of(o)) {
+ case PDF_NAME:
+ code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)o, stream_dict, page_dict, (pdf_obj **)&oc_dict);
+ if(code < 0)
+ goto exit;
+ if (pdfi_type_of(oc_dict) != PDF_DICT) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit;
+ }
+ objarray[1] = (pdf_obj *)oc_dict;
+ break;
+ case PDF_DICT:
+ objarray[1] = o;
+ break;
+ default:
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");
@@ -605,8 +631,8 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
/* 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 (properties->type != PDF_NAME)
+ properties = (pdf_name *)o;
+ if (pdfi_type_of(properties) != PDF_NAME)
goto exit;
/* If it's a name, look it up in Properties */
@@ -614,7 +640,7 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
(pdf_dict *)stream_dict, page_dict, (pdf_obj **)&oc_dict);
if (code != 0)
goto exit;
- if (oc_dict->type != PDF_DICT)
+ if (pdfi_type_of(oc_dict) != PDF_DICT)
goto exit;
/* Now we have an OC dict, see if it's visible */
@@ -625,7 +651,8 @@ int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
exit:
if (objarray != NULL)
gs_free_object(ctx->memory, objarray, "free pdfi_op_BDC");
- pdfi_pop(ctx, 2); /* pop args */
+ pdfi_countdown(o);
+ pdfi_countdown(tag);
pdfi_countdown(oc_dict);
return code;
}
diff --git a/pdf/pdf_page.c b/pdf/pdf_page.c
index f2389fea..b413b68d 100644
--- a/pdf/pdf_page.c
+++ b/pdf/pdf_page.c
@@ -56,7 +56,7 @@ static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
if (code < 0)
return code;
- if (o->type == PDF_INDIRECT) {
+ if (pdfi_type_of(o) == PDF_INDIRECT) {
if (((pdf_indirect_ref *)o)->ref_object_num == page_dict->object_num)
return_error(gs_error_circular_reference);
@@ -77,7 +77,7 @@ static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
}
ctx->encryption.decrypt_strings = false;
- if (o->type == PDF_ARRAY) {
+ if (pdfi_type_of(o) == PDF_ARRAY) {
pdf_array *a = (pdf_array *)o;
for (i=0;i < pdfi_array_size(a); i++) {
@@ -85,13 +85,13 @@ static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
code = pdfi_array_get_no_deref(ctx, a, i, (pdf_obj **)&r);
if (code < 0)
goto page_error;
- if (r->type == PDF_STREAM) {
+ if (pdfi_type_of (r) == PDF_STREAM) {
code = pdfi_interpret_content_stream(ctx, NULL, (pdf_stream *)r, page_dict);
pdfi_countdown(r);
if (code < 0)
goto page_error;
} else {
- if (r->type != PDF_INDIRECT) {
+ if (pdfi_type_of(r) != PDF_INDIRECT) {
pdfi_countdown(r);
code = gs_note_error(gs_error_typecheck);
goto page_error;
@@ -108,7 +108,7 @@ static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
code = 0;
goto page_error;
}
- if (o1->type != PDF_STREAM) {
+ if (pdfi_type_of(o1) != PDF_STREAM) {
pdfi_countdown(o1);
code = gs_note_error(gs_error_typecheck);
goto page_error;
@@ -123,7 +123,7 @@ static int pdfi_process_page_contents(pdf_context *ctx, pdf_dict *page_dict)
}
}
} else {
- if (o->type == PDF_STREAM) {
+ if (pdfi_type_of(o) == PDF_STREAM) {
code = pdfi_interpret_content_stream(ctx, NULL, (pdf_stream *)o, page_dict);
} else {
pdfi_countdown(o);
@@ -295,14 +295,23 @@ static int pdfi_set_media_size(pdf_context *ctx, pdf_dict *page_dict)
if (a == NULL) {
code = pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a);
if (code >= 0 && pdfi_array_size(a) >= 4) {
+ pdf_obj *box_obj = NULL;
+
for (i=0;i<4;i++) {
- code = pdfi_array_get_number(ctx, a, i, &d_crop[i]);
- d_crop[i] *= userunit;
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &d_crop[i]);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0)
+ break;
}
pdfi_countdown(a);
- normalize_rectangle(d_crop);
- memcpy(ctx->page.Crop, d_crop, 4 * sizeof(double));
- do_crop = true;
+ if (code >= 0) {
+ normalize_rectangle(d_crop);
+ memcpy(ctx->page.Crop, d_crop, 4 * sizeof(double));
+ do_crop = true;
+ }
}
a = default_media;
}
@@ -313,7 +322,20 @@ static int pdfi_set_media_size(pdf_context *ctx, pdf_dict *page_dict)
ctx->page.UserUnit = userunit;
for (i=0;i<4;i++) {
- code = pdfi_array_get_number(ctx, a, i, &d[i]);
+ pdf_obj *box_obj = NULL;
+
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &d[i]);
+ pdfi_countdown(box_obj);
+ }
+
+ if (code < 0) {
+ pdfi_countdown(a);
+ pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_get_media_size", NULL);
+ code = gs_erasepage(ctx->pgs);
+ return 0;
+ }
d[i] *= userunit;
}
pdfi_countdown(a);
@@ -458,26 +480,21 @@ static void pdfi_setup_transfers(pdf_context *ctx)
}
}
-static int store_box(pdf_context *ctx, float *box, pdf_array *a)
-{
- double f;
- int code = 0, i;
-
- for (i=0;i < 4;i++) {
- code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f);
- if (code < 0)
- return code;
- box[i] = (float)f;
- }
- return 0;
-}
-
-int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_info_t *info)
+/* Return a dictionary containing information about the page. Basic information is that
+ * required to render the page; if extended is true then additionally contains an
+ * array of spot ink names and an array of dictionaries each of which contains
+ * information about a font used on the page. THis is normally only used for tools
+ * like pdf_info.ps
+ */
+int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_dict **info, bool extended)
{
- int code = 0;
- pdf_dict *page_dict = NULL;
+ int code = 0, i=0;
+ pdf_dict *page_dict = NULL, *info_dict = NULL;
+ pdf_array *fonts_array = NULL, *spots_array = NULL;
pdf_array *a = NULL;
- double dbl = 0.0;
+ pdf_obj *o = NULL;
+ bool known = false;
+ double dummy;
code = pdfi_page_get_dict(ctx, page_num, &page_dict);
if (code < 0)
@@ -488,79 +505,202 @@ int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_info_t *info)
goto done;
}
- code = pdfi_check_page(ctx, page_dict, false);
+ code = pdfi_dict_alloc(ctx, 6, &info_dict);
if (code < 0)
goto done;
- info->boxes = BOX_NONE;
+ pdfi_countup(info_dict);
+
+ if (extended)
+ code = pdfi_check_page(ctx, page_dict, &fonts_array, &spots_array, false);
+ else
+ code = pdfi_check_page(ctx, page_dict, NULL, NULL, false);
+ if (code < 0)
+ goto done;
+
+ if (spots_array != NULL) {
+ code = pdfi_dict_put(ctx, info_dict, "Spots", (pdf_obj *)spots_array);
+ if (code < 0)
+ goto done;
+ pdfi_countdown(spots_array);
+ }
+
+ if (fonts_array != NULL) {
+ code = pdfi_dict_put(ctx, info_dict, "Fonts", (pdf_obj *)fonts_array);
+ if (code < 0)
+ goto done;
+ pdfi_countdown(fonts_array);
+ }
+
code = pdfi_dict_get_type(ctx, page_dict, "MediaBox", PDF_ARRAY, (pdf_obj **)&a);
if (code < 0)
pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_page_info", NULL);
if (code >= 0) {
- code = store_box(ctx, (float *)&info->MediaBox, a);
+ pdf_obj *box_obj = NULL;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &dummy);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0) {
+ pdfi_set_warning(ctx, code, NULL, W_PDF_BAD_MEDIABOX, "pdfi_page_info", NULL);
+ goto done;
+ }
+ }
+
+ code = pdfi_dict_put(ctx, info_dict, "MediaBox", (pdf_obj *)a);
if (code < 0)
goto done;
- info->boxes |= MEDIA_BOX;
pdfi_countdown(a);
a = NULL;
}
code = pdfi_dict_get_type(ctx, page_dict, "ArtBox", PDF_ARRAY, (pdf_obj **)&a);
if (code >= 0) {
- code = store_box(ctx, (float *)&info->ArtBox, a);
- if (code < 0)
- goto done;
- info->boxes |= ART_BOX;
+ pdf_obj *box_obj = NULL;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &dummy);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0)
+ break;
+ }
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, info_dict, "ArtBox", (pdf_obj *)a);
+ if (code < 0)
+ goto done;
+ }
pdfi_countdown(a);
a = NULL;
}
code = pdfi_dict_get_type(ctx, page_dict, "CropBox", PDF_ARRAY, (pdf_obj **)&a);
if (code >= 0) {
- code = store_box(ctx, (float *)&info->CropBox, a);
- if (code < 0)
- goto done;
- info->boxes |= CROP_BOX;
+ pdf_obj *box_obj = NULL;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &dummy);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0)
+ break;
+ }
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, info_dict, "CropBox", (pdf_obj *)a);
+ if (code < 0)
+ goto done;
+ }
pdfi_countdown(a);
a = NULL;
}
code = pdfi_dict_get_type(ctx, page_dict, "TrimBox", PDF_ARRAY, (pdf_obj **)&a);
if (code >= 0) {
- code = store_box(ctx, (float *)&info->TrimBox, a);
- if (code < 0)
- goto done;
- info->boxes |= TRIM_BOX;
+ pdf_obj *box_obj = NULL;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &dummy);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0)
+ break;
+ }
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, info_dict, "TrimBox", (pdf_obj *)a);
+ if (code < 0)
+ goto done;
+ }
pdfi_countdown(a);
a = NULL;
}
code = pdfi_dict_get_type(ctx, page_dict, "BleedBox", PDF_ARRAY, (pdf_obj **)&a);
if (code >= 0) {
- code = store_box(ctx, (float *)&info->BleedBox, a);
- if (code < 0)
- goto done;
- info->boxes |= BLEED_BOX;
+ pdf_obj *box_obj = NULL;
+
+ for (i = 0;i < pdfi_array_size(a); i++) {
+ code = pdfi_array_get_no_store_R(ctx, a, i, &box_obj);
+ if (code >= 0) {
+ code = pdfi_obj_to_real(ctx, box_obj, &dummy);
+ pdfi_countdown(box_obj);
+ }
+ if (code < 0)
+ break;
+ }
+ if (code >= 0) {
+ code = pdfi_dict_put(ctx, info_dict, "BleedBox", (pdf_obj *)a);
+ if (code < 0)
+ goto done;
+ }
pdfi_countdown(a);
a = NULL;
}
code = 0;
- dbl = info->Rotate = 0;
- code = pdfi_dict_get_number(ctx, page_dict, "Rotate", &dbl);
- code = 0;
- info->Rotate = dbl;
+ code = pdfi_dict_get(ctx, page_dict, "Rotate", &o);
+ if (code >= 0) {
+ if (pdfi_type_of(o) == PDF_INT || pdfi_type_of(o) == PDF_REAL) {
+ code = pdfi_dict_put(ctx, info_dict, "Rotate", o);
+ if (code < 0)
+ goto done;
+ }
+ pdfi_countdown(o);
+ }
- dbl = info->UserUnit = 1;
- code = pdfi_dict_get_number(ctx, page_dict, "UserUnit", &dbl);
- code = 0;
- info->UserUnit = dbl;
+ code = pdfi_dict_get(ctx, page_dict, "UserUnit", &o);
+ if (code >= 0) {
+ if (pdfi_type_of(o) == PDF_INT || pdfi_type_of(o) == PDF_REAL) {
+ code = pdfi_dict_put(ctx, info_dict, "UserUnit", o);
+ if (code < 0)
+ goto done;
+ }
+ pdfi_countdown(o);
+ }
+
+ if (ctx->page.has_transparency)
+ code = pdfi_dict_put(ctx, info_dict, "UsesTransparency", PDF_TRUE_OBJ);
+ else
+ code = pdfi_dict_put(ctx, info_dict, "UsesTransparency", PDF_FALSE_OBJ);
+ if (code < 0)
+ goto done;
+
+ code = pdfi_dict_known(ctx, page_dict, "Annots", &known);
+ if (code >= 0 && known)
+ code = pdfi_dict_put(ctx, info_dict, "Annots", PDF_TRUE_OBJ);
+ else
+ code = pdfi_dict_put(ctx, info_dict, "Annots", PDF_FALSE_OBJ);
+ if (code < 0)
+ goto done;
- info->HasTransparency = ctx->page.has_transparency;
- info->NumSpots = ctx->page.num_spots;
+ code = pdfi_object_alloc(ctx, PDF_INT, 0, &o);
+ if (code >= 0) {
+ pdfi_countup(o);
+ ((pdf_num *)o)->value.i = ctx->page.num_spots;
+ code = pdfi_dict_put(ctx, info_dict, "NumSpots", o);
+ pdfi_countdown(o);
+ o = NULL;
+ if (code < 0)
+ goto done;
+ }
done:
+ if (code < 0) {
+ pdfi_countdown(info_dict);
+ info_dict = NULL;
+ *info = NULL;
+ } else
+ *info = info_dict;
+
pdfi_countdown(a);
pdfi_countdown(page_dict);
return code;
@@ -585,7 +725,7 @@ int pdfi_page_get_dict(pdf_context *ctx, uint64_t page_num, pdf_dict **dict)
code = pdfi_dict_get(ctx, ctx->Root, "Pages", &o);
if (code < 0)
goto page_error;
- if (o->type != PDF_DICT) {
+ if (pdfi_type_of(o) != PDF_DICT) {
code = gs_note_error(gs_error_typecheck);
goto page_error;
}
@@ -663,14 +803,35 @@ int pdfi_page_get_number(pdf_context *ctx, pdf_dict *target_dict, uint64_t *page
static void release_page_DefaultSpaces(pdf_context *ctx)
{
if (ctx->page.DefaultGray_cs != NULL) {
+ if (ctx->page.DefaultGray_cs->interpreter_data != NULL) {
+ pdf_obj *o = (pdf_obj *)(ctx->page.DefaultGray_cs->interpreter_data);
+ if (o != NULL && pdfi_type_of(o) == PDF_NAME) {
+ pdfi_countdown(o);
+ ctx->page.DefaultGray_cs->interpreter_data = NULL;
+ }
+ }
rc_decrement(ctx->page.DefaultGray_cs, "pdfi_page_render");
ctx->page.DefaultGray_cs = NULL;
}
if (ctx->page.DefaultRGB_cs != NULL) {
+ if (ctx->page.DefaultRGB_cs->interpreter_data != NULL) {
+ pdf_obj *o = (pdf_obj *)(ctx->page.DefaultRGB_cs->interpreter_data);
+ if (o != NULL && pdfi_type_of(o) == PDF_NAME) {
+ pdfi_countdown(o);
+ ctx->page.DefaultRGB_cs->interpreter_data = NULL;
+ }
+ }
rc_decrement(ctx->page.DefaultRGB_cs, "pdfi_page_render");
ctx->page.DefaultRGB_cs = NULL;
}
if (ctx->page.DefaultCMYK_cs != NULL) {
+ if (ctx->page.DefaultCMYK_cs->interpreter_data != NULL) {
+ pdf_obj *o = (pdf_obj *)(ctx->page.DefaultCMYK_cs->interpreter_data);
+ if (o != NULL && pdfi_type_of(o) == PDF_NAME) {
+ pdfi_countdown(o);
+ ctx->page.DefaultCMYK_cs->interpreter_data = NULL;
+ }
+ }
rc_decrement(ctx->page.DefaultCMYK_cs, "pdfi_page_render");
ctx->page.DefaultCMYK_cs = NULL;
}
@@ -684,6 +845,12 @@ static int setup_page_DefaultSpaces(pdf_context *ctx, pdf_dict *page_dict)
return(pdfi_setup_DefaultSpaces(ctx, page_dict));
}
+static bool
+pdfi_pattern_purge_all_proc(gx_color_tile * ctile, void *proc_data)
+{
+ return true;
+}
+
int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
{
int code, code1=0;
@@ -714,7 +881,7 @@ int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics)
pdfi_device_set_flags(ctx);
- code = pdfi_check_page(ctx, page_dict, init_graphics);
+ code = pdfi_check_page(ctx, page_dict, NULL, NULL, init_graphics);
if (code < 0)
goto exit3;
@@ -729,8 +896,12 @@ 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);
+ /* Ignore errors retrieving the Group dictionary, we will just ignore it. This allows us
+ * to handle files such as Bug #705206 where the Group dictionary is a free object in a
+ * compressed object stream.
+ */
if (code < 0)
- goto exit3;
+ pdfi_set_error(ctx, 0, NULL, E_BAD_GROUP_DICT, "pdfi_page_render", NULL);
if (group_dict != NULL)
page_group_known = true;
@@ -864,7 +1035,12 @@ exit3:
release_page_DefaultSpaces(ctx);
- if (code == 0 || (!ctx->args.pdfstoponerror && code != gs_error_stackoverflow))
+ /* Flush any pattern tiles. We don't want to (potentially) return to PostScript
+ * with any pattern tiles referencing our objects, in case the garbager runs.
+ */
+ gx_pattern_cache_winnow(gstate_pattern_cache(ctx->pgs), pdfi_pattern_purge_all_proc, NULL);
+
+ if (code == 0 || (!ctx->args.pdfstoponerror && code != gs_error_pdf_stackoverflow))
if (!page_dict_error && ctx->finish_page != NULL)
code = ctx->finish_page(ctx);
return code;
diff --git a/pdf/pdf_page.h b/pdf/pdf_page.h
index b5fd3e2a..156f3794 100644
--- a/pdf/pdf_page.h
+++ b/pdf/pdf_page.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
@@ -18,30 +18,8 @@
#ifndef PDF_PAGE_OPERATORS
#define PDF_PAGE_OPERATORS
-typedef enum pdfi_box_enum_e {
- BOX_NONE = 0,
- MEDIA_BOX = 1,
- CROP_BOX = 2,
- TRIM_BOX = 4,
- ART_BOX = 8,
- BLEED_BOX = 16
-}pdfi_box_enum;
-
-typedef struct {
- bool HasTransparency;
- int NumSpots;
- pdfi_box_enum boxes;
- float MediaBox[4];
- float CropBox[4];
- float ArtBox[4];
- float BleedBox[4];
- float TrimBox[4];
- float Rotate;
- float UserUnit;
-} pdf_info_t;
-
int pdfi_page_render(pdf_context *ctx, uint64_t page_num, bool init_graphics);
-int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_info_t *info);
+int pdfi_page_info(pdf_context *ctx, uint64_t page_num, pdf_dict **info_dict, bool extended);
int pdfi_page_graphics_begin(pdf_context *ctx);
int pdfi_page_get_dict(pdf_context *ctx, uint64_t page_num, pdf_dict **dict);
int pdfi_page_get_number(pdf_context *ctx, pdf_dict *target_dict, uint64_t *page_num);
diff --git a/pdf/pdf_path.c b/pdf/pdf_path.c
index a9724def..56a59b07 100644
--- a/pdf/pdf_path.c
+++ b/pdf/pdf_path.c
@@ -26,88 +26,227 @@
#include "gspath.h" /* For gs_moveto() and friends */
#include "gspaint.h" /* For gs_fill() and friends */
-int pdfi_moveto (pdf_context *ctx)
+typedef enum path_segment_e {
+ pdfi_moveto_seg,
+ pdfi_lineto_seg,
+ pdfi_curveto_seg,
+ pdfi_re_seg,
+ pdfi_v_curveto_seg,
+ pdfi_y_curveto_seg,
+ pdfi_closepath_seg
+} pdfi_path_segment;
+
+static int StorePathSegment(pdf_context *ctx, pdfi_path_segment segment, double *pts)
{
- pdf_num *n1, *n2;
- int code;
- double x, y;
+ int size = 0;
+
+ switch (segment)
+ {
+ case pdfi_moveto_seg:
+ case pdfi_lineto_seg:
+ size = 2;
+ break;
+ case pdfi_re_seg:
+ case pdfi_v_curveto_seg:
+ case pdfi_y_curveto_seg:
+ size = 4;
+ break;
+ case pdfi_curveto_seg:
+ size = 6;
+ break;
+ case pdfi_closepath_seg:
+ break;
+ default:
+ return_error(gs_error_undefined);
+ break;
+ }
+ if (ctx->PathSegments == NULL) {
+ ctx->PathSegments = (char *)gs_alloc_bytes(ctx->memory, 1024, "StorePathSegment");
+ if (ctx->PathSegments == NULL)
+ return_error(gs_error_VMerror);
+ ctx->PathSegmentsCurrent = ctx->PathSegments;
+ ctx->PathSegmentsTop = ctx->PathSegments + 1024;
+ }
+ if (ctx->PathSegmentsCurrent == ctx->PathSegmentsTop) {
+ char *new_accumulator = NULL;
+ uint64_t old_size;
+
+ old_size = ctx->PathSegmentsCurrent - ctx->PathSegments;
+ new_accumulator = (char *)gs_alloc_bytes(ctx->memory, old_size + 1024, "StorePathSegment");
+ if (new_accumulator == NULL)
+ return_error(gs_error_VMerror);
+ memcpy(new_accumulator, ctx->PathSegments, old_size);
+ ctx->PathSegmentsCurrent = new_accumulator + old_size;
+ gs_free_object(ctx->memory, ctx->PathSegments, "StorePathSegment");
+ ctx->PathSegments = new_accumulator;
+ ctx->PathSegmentsTop = ctx->PathSegments + old_size + 1024;
+ }
- if (ctx->text.BlockDepth != 0)
- pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
+ if (ctx->PathPts == NULL) {
+ ctx->PathPts = (double *)gs_alloc_bytes(ctx->memory, 4096, "StorePathSegment");
+ if (ctx->PathPts == NULL)
+ return_error(gs_error_VMerror);
+ ctx->PathPtsCurrent = ctx->PathPts;
+ ctx->PathPtsTop = ctx->PathPts + (4096 / sizeof(double));
+ }
+ if (ctx->PathPtsCurrent + size > ctx->PathPtsTop) {
+ double *new_accumulator = NULL;
+ uint64_t old_size;
+
+ old_size = (char *)ctx->PathPtsCurrent - (char *)ctx->PathPts;
+ new_accumulator = (double *)gs_alloc_bytes(ctx->memory, old_size + 4096, "StorePathSegment");
+ if (new_accumulator == NULL)
+ return_error(gs_error_VMerror);
+ memcpy(new_accumulator, ctx->PathPts, old_size);
+ ctx->PathPtsCurrent = new_accumulator + (old_size / sizeof(double));
+ gs_free_object(ctx->memory, ctx->PathPts, "StorePathSegment");
+ ctx->PathPts = new_accumulator;
+ ctx->PathPtsTop = ctx->PathPts + ((old_size + 4096) / sizeof(double));
+ }
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
+ *(ctx->PathSegmentsCurrent++) = (char)segment;
+ switch (segment)
+ {
+ case pdfi_moveto_seg:
+ case pdfi_lineto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 2 * sizeof(double));
+ ctx->PathPtsCurrent += 2;
+ break;
+ case pdfi_re_seg:
+ case pdfi_v_curveto_seg:
+ case pdfi_y_curveto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 4 * sizeof(double));
+ ctx->PathPtsCurrent += 4;
+ break;
+ case pdfi_curveto_seg:
+ memcpy(ctx->PathPtsCurrent, pts, 6 * sizeof(double));
+ ctx->PathPtsCurrent += 6;
+ break;
+ case pdfi_closepath_seg:
+ break;
}
+ return 0;
+}
- n1 = (pdf_num *)ctx->stack_top[-1];
- n2 = (pdf_num *)ctx->stack_top[-2];
- if (n1->type == PDF_INT){
- y = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- y = n1->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
+static int ApplyStoredPath(pdf_context *ctx)
+{
+ int code = 0;
+ char *op = NULL;
+ double *dpts = NULL;
+
+ if (ctx->PathSegments == NULL)
+ return 0;
+
+ if (ctx->PathPts == NULL) {
+ code = gs_note_error(gs_error_unknownerror);
+ goto error;
+ }
+
+ if (ctx->pgs->current_point_valid) {
+ code = gs_newpath(ctx->pgs);
+ if (code < 0)
+ goto error;
}
- if (n2->type == PDF_INT){
- x = (double)n2->value.i;
- } else{
- if (n2->type == PDF_REAL) {
- x = n2->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
+
+ op = ctx->PathSegments;
+ dpts = ctx->PathPts;
+
+ while (op < ctx->PathSegmentsCurrent) {
+ if (dpts > ctx->PathPtsCurrent) {
+ code = gs_note_error(gs_error_unknownerror);
+ goto error;
}
+
+ switch(*op++) {
+ case pdfi_moveto_seg:
+ code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
+ dpts+= 2;
+ break;
+ case pdfi_lineto_seg:
+ code = gs_lineto(ctx->pgs, dpts[0], dpts[1]);
+ dpts+= 2;
+ break;
+ case pdfi_re_seg:
+ code = gs_moveto(ctx->pgs, dpts[0], dpts[1]);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, dpts[2], 0);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, 0, dpts[3]);
+ if (code >= 0) {
+ code = gs_rlineto(ctx->pgs, -dpts[2], 0);
+ if (code >= 0)
+ code = gs_closepath(ctx->pgs);
+ }
+ }
+ }
+ dpts+= 4;
+ break;
+ case pdfi_v_curveto_seg:
+ {
+ gs_point pt;
+
+ code = gs_currentpoint(ctx->pgs, &pt);
+ if (code >= 0) {
+ code = gs_curveto(ctx->pgs, pt.x, pt.y, dpts[0], dpts[1], dpts[2], dpts[3]);
+ dpts+= 4;
+ }
+ }
+ break;
+ case pdfi_y_curveto_seg:
+ code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[2], dpts[3]);
+ dpts+= 4;
+ break;
+ case pdfi_curveto_seg:
+ code = gs_curveto(ctx->pgs, dpts[0], dpts[1], dpts[2], dpts[3], dpts[4], dpts[5]);
+ dpts+= 6;
+ break;
+ case pdfi_closepath_seg:
+ code = gs_closepath(ctx->pgs);
+ break;
+ default:
+ code = gs_note_error(gs_error_rangecheck);
+ break;
+ }
+ if (code < 0)
+ break;
}
- code = gs_moveto(ctx->pgs, x, y);
- pdfi_pop(ctx, 2);
+error:
+ gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
+ ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
+ gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
+ ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
return code;
}
+int pdfi_moveto (pdf_context *ctx)
+{
+ int code;
+ double xy[2];
+
+ if (ctx->text.BlockDepth != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_moveto", NULL);
+
+ code = pdfi_destack_reals(ctx, xy, 2);
+ if (code < 0)
+ return code;
+
+ return StorePathSegment(ctx, pdfi_moveto_seg, (double *)&xy);
+}
+
int pdfi_lineto (pdf_context *ctx)
{
- pdf_num *n1, *n2;
int code;
- double x, y;
+ double xy[2];
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_lineto", NULL);
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- n1 = (pdf_num *)ctx->stack_top[-1];
- n2 = (pdf_num *)ctx->stack_top[-2];
- if (n1->type == PDF_INT){
- y = (double)n1->value.i;
- } else{
- if (n1->type == PDF_REAL) {
- y = n1->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
- }
- if (n2->type == PDF_INT){
- x = (double)n2->value.i;
- } else{
- if (n2->type == PDF_REAL) {
- x = n2->value.d;
- } else {
- pdfi_pop(ctx, 2);
- return_error(gs_error_typecheck);
- }
- }
+ code = pdfi_destack_reals(ctx, xy, 2);
+ if (code < 0)
+ return code;
- code = gs_lineto(ctx->pgs, x, y);
- pdfi_pop(ctx, 2);
- return code;
+ return StorePathSegment(ctx, pdfi_lineto_seg, (double *)&xy);
}
static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
@@ -121,6 +260,10 @@ static int pdfi_fill_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+
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
@@ -171,8 +314,9 @@ int pdfi_stroke(pdf_context *ctx)
if (pdfi_oc_is_off(ctx))
goto exit;
-/* code = pdfi_gsave(ctx);
- if (code < 0) goto exit;*/
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
gs_swapcolors_quick(ctx->pgs);
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_Stroke);
@@ -190,9 +334,6 @@ int pdfi_stroke(pdf_context *ctx)
}
gs_swapcolors_quick(ctx->pgs);
-/* code1 = pdfi_grestore(ctx);
- if (code == 0) code = code1;*/
-
exit:
code1 = pdfi_newpath(ctx);
if (code == 0) code = code1;
@@ -207,127 +348,64 @@ int pdfi_closepath_stroke(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath_stroke", NULL);
- code = gs_closepath(ctx->pgs);
- if (code == 0)
- code = pdfi_stroke(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_stroke(ctx);
}
int pdfi_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[6];
- if (pdfi_count_stack(ctx) < 6) {
- pdfi_clearstack(ctx);
- pdfi_set_error(ctx, 0, NULL, E_PDF_STACKUNDERFLOWERROR, "pdfi_curveto", NULL);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 6;i++){
- num = (pdf_num *)ctx->stack_top[i - 6];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 6);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 6);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_curveto", NULL);
- code = gs_curveto(ctx->pgs, Values[0], Values[1], Values[2], Values[3], Values[4], Values[5]);
- pdfi_pop(ctx, 6);
- return code;
+ return StorePathSegment(ctx, pdfi_curveto_seg, (double *)&Values);
}
int pdfi_v_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- gs_point pt;
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_v_curveto", NULL);
- code = gs_currentpoint(ctx->pgs, &pt);
- if (code < 0) {
- pdfi_pop(ctx, 4);
- return code;
- }
-
- code = gs_curveto(ctx->pgs, pt.x, pt.y, Values[0], Values[1], Values[2], Values[3]);
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_v_curveto_seg, (double *)&Values);
}
int pdfi_y_curveto(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_y_curveto", NULL);
- code = gs_curveto(ctx->pgs, Values[0], Values[1], Values[2], Values[3], Values[2], Values[3]);
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_y_curveto_seg, (double *)&Values);
}
int pdfi_closepath(pdf_context *ctx)
{
- int code = gs_closepath(ctx->pgs);
-
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_closepath", NULL);
- return code;
+ return StorePathSegment(ctx, pdfi_closepath_seg, NULL);
}
int pdfi_newpath(pdf_context *ctx)
@@ -335,8 +413,13 @@ int pdfi_newpath(pdf_context *ctx)
int code = 0, code1;
/* This code is to deal with the wacky W and W* operators */
- if (ctx->pgs->current_point_valid) {
- if (ctx->clip_active) {
+ if (ctx->clip_active) {
+ if (ctx->PathSegments != NULL) {
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+ }
+ if (ctx->pgs->current_point_valid) {
if (ctx->do_eoclip)
code = gs_eoclip(ctx->pgs);
else
@@ -345,6 +428,13 @@ int pdfi_newpath(pdf_context *ctx)
}
ctx->clip_active = false;
+ if (ctx->PathSegments != NULL){
+ gs_free_object(ctx->memory, ctx->PathSegments, "ApplyStoredPath");
+ ctx->PathSegmentsTop = ctx->PathSegmentsCurrent = ctx->PathSegments = NULL;
+ gs_free_object(ctx->memory, ctx->PathPts, "ApplyStoredPath");
+ ctx->PathPtsTop = ctx->PathPtsCurrent = ctx->PathPts = NULL;
+ }
+
code1 = gs_newpath(ctx->pgs);
if (code == 0) code = code1;
@@ -361,10 +451,11 @@ int pdfi_b(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b", NULL);
- code = gs_closepath(ctx->pgs);
- if (code >= 0)
- code = pdfi_B(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_B(ctx);
}
int pdfi_b_star(pdf_context *ctx)
@@ -374,10 +465,11 @@ int pdfi_b_star(pdf_context *ctx)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_b_star", NULL);
- code = gs_closepath(ctx->pgs);
- if (code >= 0)
- code = pdfi_B_star(ctx);
- return code;
+ code = StorePathSegment(ctx, pdfi_closepath_seg, NULL);
+ if (code < 0)
+ return code;
+
+ return pdfi_B_star(ctx);
}
/* common code for B and B* */
@@ -392,6 +484,10 @@ static int pdfi_B_inner(pdf_context *ctx, bool use_eofill)
if (pdfi_oc_is_off(ctx))
goto exit;
+ code = ApplyStoredPath(ctx);
+ if (code < 0)
+ return code;
+
code = pdfi_trans_setup(ctx, &state, NULL, TRANSPARENCY_Caller_FillStroke);
if (code == 0) {
code = pdfi_gsave(ctx);
@@ -448,45 +544,15 @@ int pdfi_eoclip(pdf_context *ctx)
int pdfi_rectpath(pdf_context *ctx)
{
- int i, code;
- pdf_num *num;
+ int code;
double Values[4];
- if (pdfi_count_stack(ctx) < 4) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- for (i=0;i < 4;i++){
- num = (pdf_num *)ctx->stack_top[i - 4];
- if (num->type != PDF_INT) {
- if(num->type != PDF_REAL) {
- pdfi_pop(ctx, 4);
- return_error(gs_error_typecheck);
- }
- else
- Values[i] = num->value.d;
- } else {
- Values[i] = (double)num->value.i;
- }
- }
+ code = pdfi_destack_reals(ctx, Values, 4);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_rectpath", NULL);
- code = gs_moveto(ctx->pgs, Values[0], Values[1]);
- if (code == 0) {
- code = gs_rlineto(ctx->pgs, Values[2], 0);
- if (code == 0){
- code = gs_rlineto(ctx->pgs, 0, Values[3]);
- if (code == 0) {
- code = gs_rlineto(ctx->pgs, -Values[2], 0);
- if (code == 0){
- code = gs_closepath(ctx->pgs);
- }
- }
- }
- }
- pdfi_pop(ctx, 4);
- return code;
+ return StorePathSegment(ctx, pdfi_re_seg, (double *)&Values);
}
diff --git a/pdf/pdf_pattern.c b/pdf/pdf_pattern.c
index 57a16449..b4bd0375 100644
--- a/pdf/pdf_pattern.c
+++ b/pdf/pdf_pattern.c
@@ -114,35 +114,12 @@ static void pdfi_free_pattern_context(pdf_pattern_context_t *context)
gs_free_object(context->ctx->memory, context, "Free pattern context");
}
-static bool
-pdfi_pattern_purge_proc(gx_color_tile * ctile, void *proc_data)
-{
- if (ctile->id == *((gx_bitmap_id *)proc_data))
- return true;
- return false;
-}
-
void pdfi_pattern_cleanup(gs_memory_t * mem, void *p)
{
gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)p;
- pdf_pattern_context_t *context;
- gx_color_tile *pctile = NULL;
-
- context = (pdf_pattern_context_t *)pinst->client_data;
- /* If are being called from Ghostscript, the clist pattern accumulator device (in
- the tile cache) *can* outlast outlast our pattern instance, so if the pattern
- instance is being freed, also remove the entry from the cache
- */
- if (context != NULL && context->ctx != NULL && context->ctx->pgs != NULL &&
- 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));
- }
-
- if (context != NULL) {
- pdfi_free_pattern_context(context);
+ if (pinst->client_data != NULL) {
+ pdfi_free_pattern_context((pdf_pattern_context_t *)pinst->client_data);
pinst->client_data = NULL;
pinst->notify_free = NULL;
}
@@ -418,7 +395,7 @@ pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_di
gs_pattern1_init(&templat);
/* Must be a stream */
- if (stream->type != PDF_STREAM) {
+ if (pdfi_type_of(stream) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto exit;
}
@@ -525,6 +502,28 @@ pdfi_setpattern_type1(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_di
cc->pattern->client_data = context;
cc->pattern->notify_free = pdfi_pattern_cleanup;
+ {
+ unsigned long hash = 5381;
+ unsigned int i;
+ const char *str = (const char *)&ctx->pgs->ctm;
+
+ gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)cc->pattern;
+
+
+ for (i = 0; i < 4 * sizeof(float); i++)
+ hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
+
+ str = (const char *)&pdict->object_num;
+ for (i = 0; i < sizeof(uint32_t); i++)
+ hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
+
+ hash = ((hash << 5) + hash) + ctx->pgs->device->color_info.num_components; /* hash * 33 + c */
+
+ /* Include num_components for case where we have softmask and non-softmask
+ fills with the same tile. We may need two tiles for this if there is a
+ change in color space for the transparency group. */
+ pinst->id = hash;
+ }
context = NULL;
code = pdfi_grestore(ctx);
diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c
index 2c2badf2..22865fe6 100644
--- a/pdf/pdf_repair.c
+++ b/pdf/pdf_repair.c
@@ -25,14 +25,14 @@
#include "pdf_misc.h"
#include "pdf_repair.h"
-static int pdfi_repair_add_object(pdf_context *ctx, uint64_t obj, uint64_t gen, gs_offset_t offset)
+static int pdfi_repair_add_object(pdf_context *ctx, int64_t obj, int64_t gen, gs_offset_t offset)
{
/* Although we can handle object numbers larger than this, on some systems (32-bit Windows)
* memset is limited to a (signed!) integer for the size of memory to clear. We could deal
* with this by clearing the memory in blocks, but really, this is almost certainly a
* corrupted file or something.
*/
- if (obj >= 0x7ffffff / sizeof(xref_entry))
+ if (obj >= 0x7ffffff / sizeof(xref_entry) || obj < 1 || gen < 0 || offset < 0)
return_error(gs_error_rangecheck);
if (ctx->xref_table == NULL) {
@@ -85,7 +85,7 @@ int pdfi_repair_file(pdf_context *ctx)
{
int code = 0;
gs_offset_t offset, saved_offset;
- uint64_t object_num = 0, generation_num = 0;
+ int64_t object_num = 0, generation_num = 0;
int i;
gs_offset_t outer_saved_offset[3];
@@ -163,18 +163,18 @@ int pdfi_repair_file(pdf_context *ctx)
goto exit;
}
if (pdfi_count_stack(ctx) > 0) {
- if (ctx->stack_top[-1]->type == PDF_KEYWORD) {
- pdf_keyword *k = (pdf_keyword *)ctx->stack_top[-1];
+ if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
+ pdf_obj *k = ctx->stack_top[-1];
pdf_num *n;
- if (k->key == TOKEN_OBJ) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
gs_offset_t saved_offset[3];
offset = outer_saved_offset[0];
saved_offset[0] = saved_offset[1] = saved_offset[2] = 0;
- if (pdfi_count_stack(ctx) < 3 || ctx->stack_top[-2]->type != PDF_INT || ctx->stack_top[-2]->type != PDF_INT) {
+ if (pdfi_count_stack(ctx) < 3 || pdfi_type_of(ctx->stack_top[-3]) != PDF_INT || pdfi_type_of(ctx->stack_top[-2]) != PDF_INT) {
pdfi_clearstack(ctx);
continue;
}
@@ -199,15 +199,15 @@ int pdfi_repair_file(pdf_context *ctx)
if (code == 0 && ctx->main_stream->eof)
break;
- if (ctx->stack_top[-1]->type == PDF_KEYWORD){
- pdf_keyword *k = (pdf_keyword *)ctx->stack_top[-1];
+ if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
+ pdf_obj *k = ctx->stack_top[-1];
- if (k->key == TOKEN_OBJ) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
/* Found obj while looking for endobj, store the existing 'obj'
* and start afresh.
*/
code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
- if (pdfi_count_stack(ctx) < 3 || ctx->stack_top[-2]->type != PDF_INT || ctx->stack_top[-2]->type != PDF_INT) {
+ if (pdfi_count_stack(ctx) < 3 || pdfi_type_of(ctx->stack_top[-3]) != PDF_INT || pdfi_type_of(ctx->stack_top[-2]) != PDF_INT) {
pdfi_clearstack(ctx);
break;
}
@@ -220,14 +220,14 @@ int pdfi_repair_file(pdf_context *ctx)
continue;
}
- if (k->key == TOKEN_ENDOBJ) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
if (code < 0)
goto exit;
pdfi_clearstack(ctx);
break;
} else {
- if (k->key == TOKEN_STREAM) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
static const char test[] = "endstream";
int index = 0;
@@ -245,27 +245,16 @@ int pdfi_repair_file(pdf_context *ctx)
index = 0;
} while (index < 9);
do {
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0) {
- if (code != gs_error_VMerror && code != gs_error_ioerror)
- continue;
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
+ if (code == gs_error_VMerror || code == gs_error_ioerror)
goto exit;
+ if (code == TOKEN_ENDOBJ || code == TOKEN_INVALID_KEY) {
+ code = pdfi_repair_add_object(ctx, object_num, generation_num, offset);
+ if (code == gs_error_VMerror || code == gs_error_ioerror)
+ goto exit;
+ break;
}
- 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;
- }
- }
- }
- }while(ctx->main_stream->eof == false);
+ } while(ctx->main_stream->eof == false);
pdfi_clearstack(ctx);
break;
@@ -277,10 +266,10 @@ int pdfi_repair_file(pdf_context *ctx)
} while(1);
break;
} else {
- if (k->key == TOKEN_ENDOBJ) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
pdfi_clearstack(ctx);
} else
- if (k->key == TOKEN_STARTXREF) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_STARTXREF)) {
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
if (code < 0 && code != gs_error_VMerror && code != gs_error_ioerror)
continue;
@@ -288,9 +277,9 @@ int pdfi_repair_file(pdf_context *ctx)
goto exit;
pdfi_clearstack(ctx);
} else {
- if (k->key == TOKEN_TRAILER) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_TRAILER)) {
code = pdfi_read_bare_object(ctx, ctx->main_stream, 0, 0, 0);
- if (code == 0 && pdfi_count_stack(ctx) > 0 && ctx->stack_top[-1]->type == PDF_DICT) {
+ if (code == 0 && pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) == PDF_DICT) {
if (ctx->Trailer) {
pdf_dict *d = (pdf_dict *)ctx->stack_top[-1];
bool known = false;
@@ -319,7 +308,7 @@ int pdfi_repair_file(pdf_context *ctx)
goto exit;
}
}
- if (pdfi_count_stack(ctx) > 0 && ctx->stack_top[-1]->type != PDF_INT)
+ if (pdfi_count_stack(ctx) > 0 && pdfi_type_of(ctx->stack_top[-1]) != PDF_INT)
pdfi_clearstack(ctx);
}
} while (ctx->main_stream->eof == false);
@@ -338,33 +327,44 @@ int pdfi_repair_file(pdf_context *ctx)
if (ctx->xref_table->xref[i].object_num != 0) {
/* At this stage, all the objects we've found must be uncompressed */
if (ctx->xref_table->xref[i].u.uncompressed.offset > ctx->main_stream_length) {
- code = gs_note_error(gs_error_rangecheck);
- goto exit;
+ /* This can only happen if we had read an xref table before we tried to repair
+ * the file, and the table has entries we didn't find in the file. So
+ * mark the entry as free, and offset of 0, and just carry on.
+ */
+ ctx->xref_table->xref[i].free = 1;
+ ctx->xref_table->xref[i].u.uncompressed.offset = 0;
+ continue;
}
pdfi_seek(ctx, ctx->main_stream, ctx->xref_table->xref[i].u.uncompressed.offset, SEEK_SET);
do {
code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (ctx->main_stream->eof == true || (code < 0 && code != gs_error_ioerror && code != gs_error_VMerror))
+ if (ctx->main_stream->eof == true || (code < 0 && code != gs_error_ioerror && code != gs_error_VMerror)) {
+ /* object offset is beyond EOF or object is broken (possibly due to multiple xref
+ * errors) ignore the error and carry on, if the object gets used then we will
+ * error out at that point.
+ */
+ code = 0;
break;
+ }
if (code < 0)
goto exit;
- if (ctx->stack_top[-1]->type == PDF_KEYWORD) {
- pdf_keyword *k = (pdf_keyword *)ctx->stack_top[-1];
+ if (pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
+ pdf_obj *k = ctx->stack_top[-1];
- if (k->key == TOKEN_OBJ){
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_OBJ)) {
continue;
}
- if (k->key == TOKEN_ENDOBJ) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_ENDOBJ)) {
if (pdfi_count_stack(ctx) > 1) {
- if (ctx->stack_top[-2]->type == PDF_DICT) {
+ if (pdfi_type_of(ctx->stack_top[-2]) == PDF_DICT) {
pdf_dict *d = (pdf_dict *)ctx->stack_top[-2];
pdf_obj *o = NULL;
code = pdfi_dict_knownget_type(ctx, d, "Type", PDF_NAME, &o);
if (code < 0) {
pdfi_clearstack(ctx);
- goto exit;
+ continue;
}
if (code > 0) {
pdf_name *n = (pdf_name *)o;
@@ -381,7 +381,7 @@ int pdfi_repair_file(pdf_context *ctx)
pdfi_clearstack(ctx);
break;
}
- if (k->key == TOKEN_STREAM) {
+ if (k == PDF_TOKEN_AS_OBJ(TOKEN_STREAM)) {
pdf_dict *d;
pdf_name *n = NULL;
@@ -390,7 +390,7 @@ int pdfi_repair_file(pdf_context *ctx)
break;;
}
d = (pdf_dict *)ctx->stack_top[-2];
- if (d->type != PDF_DICT) {
+ if (pdfi_type_of(d) != PDF_DICT) {
pdfi_clearstack(ctx);
break;;
}
@@ -403,10 +403,10 @@ int pdfi_repair_file(pdf_context *ctx)
}
if (code > 0) {
if (pdfi_name_is(n, "ObjStm")) {
- int64_t N, obj_num, offset;
+ int64_t N;
+ int obj_num, offset;
int j;
pdf_c_stream *compressed_stream;
- pdf_obj *o;
pdf_stream *stream;
offset = pdfi_unread_tell(ctx);
@@ -422,36 +422,28 @@ int pdfi_repair_file(pdf_context *ctx)
code = pdfi_dict_get_int(ctx, d, "N", &N);
if (code == 0) {
for (j=0;j < N; j++) {
- code = pdfi_read_token(ctx, compressed_stream, 0, 0);
- if (code == 0)
+ code = pdfi_read_bare_int(ctx, compressed_stream, &obj_num);
+ 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) {
- o = ctx->stack_top[-1];
- if (((pdf_obj *)o)->type == PDF_INT) {
- offset = ((pdf_num *)o)->value.i;
- if (obj_num < 1) {
- pdfi_close_file(ctx, compressed_stream);
- pdfi_clearstack(ctx);
- code = gs_note_error(gs_error_rangecheck);
- goto exit;
- }
- 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;
- }
- }
+ else {
+ code = pdfi_read_bare_int(ctx, compressed_stream, &offset);
+ if (code > 0) {
+ if (obj_num < 1) {
+ pdfi_close_file(ctx, compressed_stream);
+ pdfi_countdown(n);
+ pdfi_clearstack(ctx);
+ code = gs_note_error(gs_error_rangecheck);
+ goto exit;
+ }
+ 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;
}
}
}
@@ -461,6 +453,7 @@ int pdfi_repair_file(pdf_context *ctx)
}
if (code < 0) {
if (ctx->args.pdfstoponerror || code == gs_error_VMerror) {
+ pdfi_countdown(n);
pdfi_clearstack(ctx);
goto exit;
}
@@ -477,6 +470,8 @@ int pdfi_repair_file(pdf_context *ctx)
}
exit:
+ if (code > 0)
+ code = 0;
pdfi_seek(ctx, ctx->main_stream, saved_offset, SEEK_SET);
ctx->main_stream->eof = false;
return code;
diff --git a/pdf/pdf_sec.c b/pdf/pdf_sec.c
index fa7131f8..999fa713 100644
--- a/pdf/pdf_sec.c
+++ b/pdf/pdf_sec.c
@@ -993,6 +993,7 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
pdf_dict *CF_dict = NULL, *StdCF_dict = NULL;
pdf_dict *d = NULL, *d1 = NULL;
pdf_obj *o = NULL;
+ bool b;
pdf_string *s = NULL;
int64_t i64;
double f;
@@ -1039,30 +1040,40 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
pdfi_countdown(o);
o = NULL;
- code = pdfi_dict_knownget_number(ctx, d, "Length", &f);
+ *KeyLen = 0;
+ ctx->encryption.V = -1;
+
+ code = pdfi_dict_get_int(ctx, d, "R", &i64);
if (code < 0)
goto done;
+ ctx->encryption.R = (int)i64;
- if (code > 0)
- *KeyLen = (int)f;
- else
- *KeyLen = 0;
-
- code = pdfi_dict_get_int(ctx, d, "V", &i64);
+ /* V is required for PDF 2.0 but only strongly recommended for earlier versions */
+ code = pdfi_dict_known(ctx, d, "V", &b);
if (code < 0)
goto done;
- if (i64 < 1 || i64 > 5) {
- code = gs_error_rangecheck;
- goto done;
- }
+ if (b) {
+ code = pdfi_dict_get_int(ctx, d, "V", &i64);
+ if (code < 0)
+ goto done;
- ctx->encryption.V = (int)i64;
+ if (i64 < 1 || i64 > 5) {
+ code = gs_error_rangecheck;
+ goto done;
+ }
- code = pdfi_dict_get_int(ctx, d, "R", &i64);
- if (code < 0)
- goto done;
- ctx->encryption.R = (int)i64;
+ ctx->encryption.V = (int)i64;
+
+ if (ctx->encryption.V == 2 || ctx->encryption.V == 3) {
+ code = pdfi_dict_knownget_number(ctx, d, "Length", &f);
+ if (code < 0)
+ goto done;
+
+ if (code > 0)
+ *KeyLen = (int)f;
+ }
+ }
code = pdfi_dict_get_int(ctx, d, "P", &i64);
if (code < 0)
@@ -1109,12 +1120,12 @@ static int pdfi_read_Encrypt_dict(pdf_context *ctx, int *KeyLen)
pdfi_countdown(s);
s = NULL;
- code = pdfi_dict_knownget_type(ctx, d, "EncryptMetadata", PDF_BOOL, &o);
+ code = pdfi_dict_knownget_bool(ctx, d, "EncryptMetadata", &b);
if (code < 0)
goto done;
if (code > 0) {
- ctx->encryption.EncryptMetadata = ((pdf_bool *)o)->value;
- pdfi_countdown(o);
+ ctx->encryption.EncryptMetadata = b;
+ code = 0;
}
else
ctx->encryption.EncryptMetadata = true;
@@ -1368,13 +1379,19 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
switch(ctx->encryption.R) {
case 2:
/* Set up the defaults if not already set */
+ /* R of 2 means V < 2 which is either algorithm 3.1 with a 40-bit key
+ * or an undocumented and unsupported algorithm.
+ */
+ if (ctx->encryption.V >= 0) {
+ if (ctx->encryption.V == 0) {
+ code = gs_note_error(gs_error_undefined);
+ goto done;
+ }
+ }
/* Revision 2 is always 40-bit RC4 */
- if (KeyLen != 0 && (KeyLen < 40 || KeyLen > 128 || KeyLen % 8 != 0)) {
+ if (KeyLen != 0 && KeyLen != 40)
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;
+ KeyLen = 40;
if (ctx->encryption.StmF == CRYPT_NONE)
ctx->encryption.StmF = CRYPT_V1;
if (ctx->encryption.StrF == CRYPT_NONE)
@@ -1383,10 +1400,17 @@ int pdfi_initialise_Decryption(pdf_context *ctx)
break;
case 3:
/* Set up the defaults if not already set */
- /* Revision 3 is always 128-bit RC4 */
- if (KeyLen != 0 && KeyLen != 128)
+ if (ctx->encryption.V >= 0) {
+ if (ctx->encryption.V == 3) {
+ code = gs_note_error(gs_error_undefined);
+ goto done;
+ }
+ }
+ /* Revision 3 *may* be more than 40 bits of RC4 */
+ if (KeyLen != 0 && (KeyLen < 40 || KeyLen > 128 || KeyLen % 8 != 0)) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_INVALID_DECRYPT_LEN, "pdfi_initialise_Decryption", NULL);
- KeyLen = 128;
+ KeyLen = 128;
+ }
if (ctx->encryption.StmF == CRYPT_NONE)
ctx->encryption.StmF = CRYPT_V2;
if (ctx->encryption.StrF == CRYPT_NONE)
diff --git a/pdf/pdf_shading.c b/pdf/pdf_shading.c
index c4e93e88..5cd347f7 100644
--- a/pdf/pdf_shading.c
+++ b/pdf/pdf_shading.c
@@ -55,13 +55,13 @@ static int pdfi_build_shading_function(pdf_context *ctx, gs_function_t **ppfn, c
if (code < 0)
goto build_shading_function_error;
- if (o->type != PDF_DICT && o->type != PDF_STREAM) {
+ if (pdfi_type_of(o) != PDF_DICT && pdfi_type_of(o) != PDF_STREAM) {
uint size;
pdf_obj *rsubfn;
gs_function_t **Functions;
int64_t i;
- if (o->type != PDF_ARRAY) {
+ if (pdfi_type_of(o) != PDF_ARRAY) {
code = gs_error_typecheck;
goto build_shading_function_error;
}
@@ -78,7 +78,7 @@ static int pdfi_build_shading_function(pdf_context *ctx, gs_function_t **ppfn, c
for (i = 0; i < size; ++i) {
code = pdfi_array_get(ctx, (pdf_array *)o, i, &rsubfn);
if (code == 0) {
- if (rsubfn->type != PDF_DICT && rsubfn->type != PDF_STREAM)
+ if (pdfi_type_of(rsubfn) != PDF_DICT && pdfi_type_of(rsubfn) != PDF_STREAM)
code = gs_note_error(gs_error_typecheck);
}
if (code < 0) {
@@ -133,7 +133,7 @@ static int pdfi_shading1(pdf_context *ctx, gs_shading_params_t *pcommon,
static const float default_Domain[4] = {0, 1, 0, 1};
pdf_dict *shading_dict;
- if (Shading->type != PDF_DICT)
+ if (pdfi_type_of(Shading) != PDF_DICT)
return_error(gs_error_typecheck);
shading_dict = (pdf_dict *)Shading;
@@ -179,7 +179,7 @@ static int pdfi_shading2(pdf_context *ctx, gs_shading_params_t *pcommon,
int code, i;
pdf_dict *shading_dict;
- if (Shading->type != PDF_DICT)
+ if (pdfi_type_of(Shading) != PDF_DICT)
return_error(gs_error_typecheck);
shading_dict = (pdf_dict *)Shading;
@@ -231,7 +231,7 @@ static int pdfi_shading3(pdf_context *ctx, gs_shading_params_t *pcommon,
int code, i;
pdf_dict *shading_dict;
- if (Shading->type != PDF_DICT)
+ if (pdfi_type_of(Shading) != PDF_DICT)
return_error(gs_error_typecheck);
shading_dict = (pdf_dict *)Shading;
@@ -285,7 +285,7 @@ static int pdfi_build_mesh_shading(pdf_context *ctx, gs_shading_mesh_params_t *p
int64_t i;
pdf_dict *shading_dict;
- if (Shading->type != PDF_STREAM)
+ if (pdfi_type_of(Shading) != PDF_STREAM)
return_error(gs_error_typecheck);
code = pdfi_dict_from_obj(ctx, Shading, &shading_dict);
@@ -634,6 +634,7 @@ static int get_shading_common(pdf_context *ctx, pdf_dict *shading_dict, gs_shadi
get_shading_common_error:
pdfi_countdown((pdf_obj *)a);
gs_free_object(ctx->memory, params->Background, "Background (common_shading_error)");
+ params->Background = NULL;
return code;
}
@@ -861,17 +862,27 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
if (ctx->text.BlockDepth != 0)
pdfi_set_warning(ctx, 0, NULL, W_PDF_OPINVALIDINTEXT, "pdfi_shading", NULL);
- if (pdfi_oc_is_off(ctx))
+ if (pdfi_oc_is_off(ctx)) {
+ pdfi_pop(ctx, 1);
return 0;
+ }
+
+ savedoffset = pdfi_tell(ctx->main_stream);
n = (pdf_name *)ctx->stack_top[-1];
- if (n->type != PDF_NAME)
- return_error(gs_error_typecheck);
+ pdfi_countup(n);
+ pdfi_pop(ctx, 1);
+
+ if (pdfi_type_of(n) != PDF_NAME) {
+ code = gs_note_error(gs_error_typecheck);
+ goto exit1;
+ }
- savedoffset = pdfi_tell(ctx->main_stream);
code = pdfi_loop_detector_mark(ctx);
- if (code < 0)
+ if (code < 0) {
+ pdfi_countdown(n);
return code;
+ }
code = pdfi_op_q(ctx);
if (code < 0)
@@ -882,7 +893,7 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
if (code < 0)
goto exit2;
- if (Shading->type != PDF_DICT && Shading->type != PDF_STREAM) {
+ if (pdfi_type_of(Shading) != PDF_DICT && pdfi_type_of(Shading) != PDF_STREAM) {
code = gs_note_error(gs_error_typecheck);
goto exit2;
}
@@ -929,7 +940,7 @@ int pdfi_shading(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
if (code == 0)
code = code1;
exit1:
- pdfi_pop(ctx, 1);
+ pdfi_countdown(n);
(void)pdfi_loop_detector_cleartomark(ctx);
pdfi_seek(ctx, ctx->main_stream, savedoffset, SEEK_SET);
return code;
diff --git a/pdf/pdf_stack.c b/pdf/pdf_stack.c
index d2644fbb..12dae267 100644
--- a/pdf/pdf_stack.c
+++ b/pdf/pdf_stack.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
@@ -49,7 +49,7 @@ int pdfi_push(pdf_context *ctx, pdf_obj *o)
if (ctx->stack_top >= ctx->stack_limit) {
if (ctx->stack_size >= MAX_STACK_SIZE)
- return_error(gs_error_stackoverflow);
+ return_error(gs_error_pdf_stackoverflow);
new_stack = (pdf_obj **)gs_alloc_bytes(ctx->memory, (ctx->stack_size + INITIAL_STACK_SIZE) * sizeof (pdf_obj *), "pdfi_push_increase_interp_stack");
if (new_stack == NULL)
@@ -106,7 +106,7 @@ int pdfi_count_to_mark(pdf_context *ctx, uint64_t *count)
*count = 0;
while (&ctx->stack_top[index] >= save_bot) {
- if (o->type == PDF_ARRAY_MARK || o->type == PDF_DICT_MARK)
+ if (pdfi_type_of(o) == PDF_ARRAY_MARK || pdfi_type_of(o) == PDF_DICT_MARK)
return 0;
o = ctx->stack_top[--index];
(*count)++;
@@ -124,3 +124,105 @@ int pdfi_clear_to_mark(pdf_context *ctx)
return code;
return pdfi_pop(ctx, count + 1);
}
+
+int
+pdfi_destack_real(pdf_context *ctx, double *d)
+{
+ int code;
+
+ if (pdfi_count_stack(ctx) < 1)
+ return_error(gs_error_stackunderflow);
+
+ code = pdfi_obj_to_real(ctx, ctx->stack_top[-1], d);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
+ }
+ pdfi_pop(ctx, 1);
+
+ return 0;
+}
+
+int
+pdfi_destack_reals(pdf_context *ctx, double *d, int n)
+{
+ int i, code;
+
+ if (pdfi_count_stack(ctx) < n) {
+ pdfi_clearstack(ctx);
+ return_error(gs_error_stackunderflow);
+ }
+
+ for (i = 0; i < n; i++) {
+ code = pdfi_obj_to_real(ctx, ctx->stack_top[i-n], &d[i]);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
+ }
+ }
+ pdfi_pop(ctx, n);
+
+ return 0;
+}
+
+int
+pdfi_destack_floats(pdf_context *ctx, float *d, int n)
+{
+ int i, code;
+
+ if (pdfi_count_stack(ctx) < n) {
+ pdfi_clearstack(ctx);
+ return_error(gs_error_stackunderflow);
+ }
+
+ for (i = 0; i < n; i++) {
+ code = pdfi_obj_to_float(ctx, ctx->stack_top[i-n], &d[i]);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
+ }
+ }
+ pdfi_pop(ctx, n);
+
+ return 0;
+}
+
+int
+pdfi_destack_int(pdf_context *ctx, int64_t *i)
+{
+ int code;
+
+ if (pdfi_count_stack(ctx) < 1)
+ return_error(gs_error_stackunderflow);
+
+ code = pdfi_obj_to_int(ctx, ctx->stack_top[-1], i);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
+ }
+ pdfi_pop(ctx, 1);
+
+ return 0;
+}
+
+int
+pdfi_destack_ints(pdf_context *ctx, int64_t *i64, int n)
+{
+ int i, code;
+
+ if (pdfi_count_stack(ctx) < n) {
+ pdfi_clearstack(ctx);
+ return_error(gs_error_stackunderflow);
+ }
+
+ for (i = 0; i < n; i++) {
+ code = pdfi_obj_to_int(ctx, ctx->stack_top[i-n], &i64[i]);
+ if (code < 0) {
+ pdfi_clearstack(ctx);
+ return code;
+ }
+ }
+ pdfi_pop(ctx, n);
+
+ return 0;
+}
diff --git a/pdf/pdf_stack.h b/pdf/pdf_stack.h
index 982cfab1..2f7d8640 100644
--- a/pdf/pdf_stack.h
+++ b/pdf/pdf_stack.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
@@ -29,60 +29,75 @@ int pdfi_mark_stack(pdf_context *ctx, pdf_obj_type type);
void pdfi_clearstack(pdf_context *ctx);
int pdfi_count_to_mark(pdf_context *ctx, uint64_t *count);
int pdfi_clear_to_mark(pdf_context *ctx);
+int pdfi_destack_real(pdf_context *ctx, double *d);
+int pdfi_destack_reals(pdf_context *ctx, double *d, int n);
+int pdfi_destack_floats(pdf_context *ctx, float *d, int n);
+int pdfi_destack_int(pdf_context *ctx, int64_t *i);
+int pdfi_destack_ints(pdf_context *ctx, int64_t *i, int n);
static inline void pdfi_countup_impl(pdf_obj *o)
{
- if (o != NULL) {
- o->refcnt++;
+ if ((uintptr_t)o < TOKEN__LAST_KEY)
+ {
#if REFCNT_DEBUG
- dmprintf3(OBJ_MEMORY(o), "Incrementing reference count of object %d, UID %lu, to %d\n", o->object_num, o->UID, o->refcnt);
+ if (o == NULL)
+ dprintf("Incrementing reference count of NULL pointer\n");
#endif
+ return;
}
+ o->refcnt++;
#if REFCNT_DEBUG
- else {
- dprintf("Incrementing reference count of NULL pointer\n");
- }
+ dmprintf3(OBJ_MEMORY(o), "Incrementing reference count of object %d, UID %lu, to %d\n", o->object_num, o->UID, o->refcnt);
#endif
}
static inline void pdfi_countdown_impl(pdf_obj *o)
{
- if (o != NULL) {
+#if defined(DEBUG) || REFCNT_DEBUG
+ pdf_context *ctx;
+#endif
+
+ /* A 'low' pointer value indicates a type that is not an
+ * actual object (typically keyword). This includes the
+ * NULL case. Nothing to free in that case. */
+ if ((uintptr_t)o < TOKEN__LAST_KEY)
+ return;
+
+#if defined(DEBUG) || REFCNT_DEBUG
+ ctx = (pdf_context *)o->ctx;
+#endif
#ifdef DEBUG
- pdf_context *ctx1 = (pdf_context *)o->ctx;
- if (o->refcnt == 0)
- emprintf(OBJ_MEMORY(o), "Decrementing object with refcount at 0!\n");
+ if (o->refcnt == 0)
+ emprintf(OBJ_MEMORY(o), "Decrementing object with refcount at 0!\n");
#endif
- o->refcnt--;
+ o->refcnt--;
#if REFCNT_DEBUG
- dmprintf3(OBJ_MEMORY(o), "Decrementing reference count of object %d, UID %lu, to %d\n", o->object_num, o->UID, o->refcnt);
+ dmprintf3(OBJ_MEMORY(o), "Decrementing reference count of object %d, UID %lu, to %d\n", o->object_num, o->UID, o->refcnt);
#endif
- if (o->refcnt == 0) {
+ if (o->refcnt != 0)
+ return;
#if REFCNT_DEBUG
- pdf_context *ctx = (pdf_context *)o->ctx;
- if (ctx != NULL && ctx->cache_entries != 0) {
- pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
-
- while(entry) {
- next = entry->next;
- if (entry->o->object_num != 0 && entry->o->object_num == o->object_num)
- dmprintf2(OBJ_MEMORY(o), "Freeing object %d, UID %lu, but there is still a cache entry!\n", o->object_num, o->UID);
- entry = next;
- }
- }
- dmprintf2(OBJ_MEMORY(o), "Freeing object %d, UID %lu\n", o->object_num, o->UID);
+ if (ctx != NULL && ctx->cache_entries != 0) {
+ pdf_obj_cache_entry *entry = ctx->cache_LRU, *next;
+
+ while(entry) {
+ next = entry->next;
+ if (entry->o->object_num != 0 && entry->o->object_num == o->object_num)
+ dmprintf2(OBJ_MEMORY(o), "Freeing object %d, UID %lu, but there is still a cache entry!\n", o->object_num, o->UID);
+ entry = next;
+ }
+ }
+ dmprintf2(OBJ_MEMORY(o), "Freeing object %d, UID %lu\n", o->object_num, o->UID);
#endif
#ifdef DEBUG
- if (ctx1->xref_table != NULL && o->object_num > 0 &&
- o->object_num < ctx1->xref_table->xref_size &&
- ctx1->xref_table->xref[o->object_num].cache != NULL &&
- ctx1->xref_table->xref[o->object_num].cache->o == o) {
- dmprintf1(OBJ_MEMORY(o), "Freeing object %d while it is still in the object cache!\n", o->object_num);
- }
-#endif
- pdfi_free_object(o);
- }
+ if (ctx->xref_table != NULL && o->object_num > 0 &&
+ o->object_num < ctx->xref_table->xref_size &&
+ ctx->xref_table->xref[o->object_num].cache != NULL &&
+ ctx->xref_table->xref[o->object_num].cache->o == o) {
+ dmprintf1(OBJ_MEMORY(o), "Freeing object %d while it is still in the object cache!\n", o->object_num);
}
+#endif
+ pdfi_free_object(o);
}
/* These two macros are present simply to add a cast to the generic object type, so that
diff --git a/pdf/pdf_text.c b/pdf/pdf_text.c
index e22f0c0e..dfc35201 100644
--- a/pdf/pdf_text.c
+++ b/pdf/pdf_text.c
@@ -188,65 +188,30 @@ static int pdfi_set_Tc(pdf_context *ctx, double Tc)
int pdfi_Tc(pdf_context *ctx)
{
- int code = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ int code;
+ double d;
- n = (pdf_num *)ctx->stack_top[-1];
+ code = pdfi_destack_real(ctx, &d);
+ if (code < 0)
+ return code;
- if (n->type == PDF_INT)
- code = pdfi_set_Tc(ctx, (double)n->value.i);
- else {
- if (n->type == PDF_REAL)
- code = pdfi_set_Tc(ctx, n->value.d);
- else
- code = gs_note_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ return pdfi_set_Tc(ctx, d);
}
int pdfi_Td(pdf_context *ctx)
{
int code;
- pdf_num *Tx = NULL, *Ty = NULL;
+ double Txy[2];
gs_matrix m, mat;
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ code = pdfi_destack_reals(ctx, Txy, 2);
+ if (code < 0)
+ return code;
gs_make_identity(&m);
- Ty = (pdf_num *)ctx->stack_top[-1];
- Tx = (pdf_num *)ctx->stack_top[-2];
-
- if (Tx->type == PDF_INT) {
- m.tx = (float)Tx->value.i;
- } else {
- if (Tx->type == PDF_REAL) {
- m.tx = (float)Tx->value.d;
- } else {
- code = gs_note_error(gs_error_typecheck);
- goto Td_error;
- }
- }
-
- if (Ty->type == PDF_INT) {
- m.ty = (float)Ty->value.i;
- } else {
- if (Ty->type == PDF_REAL) {
- m.ty = (float)Ty->value.d;
- } else {
- code = gs_note_error(gs_error_typecheck);
- goto Td_error;
- }
- }
+ m.tx = Txy[0];
+ m.ty = Txy[1];
if (ctx->text.BlockDepth == 0) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_TEXTOPNOBT, "pdfi_Td", NULL);
@@ -254,70 +219,38 @@ int pdfi_Td(pdf_context *ctx)
gs_make_identity(&mat);
code = gs_settextmatrix(ctx->pgs, &mat);
if (code < 0)
- goto Td_error;
+ return code;
code = gs_settextlinematrix(ctx->pgs, &mat);
if (code < 0)
- goto Td_error;
+ return code;
}
code = gs_matrix_multiply(&m, &ctx->pgs->textlinematrix, &mat);
if (code < 0)
- goto Td_error;
+ return code;
code = gs_settextmatrix(ctx->pgs, (gs_matrix *)&mat);
if (code < 0)
- goto Td_error;
-
- code = gs_settextlinematrix(ctx->pgs, (gs_matrix *)&mat);
- if (code < 0)
- goto Td_error;
-
- pdfi_pop(ctx, 2);
- return code;
+ return code;
-Td_error:
- pdfi_pop(ctx, 2);
- return code;
+ return gs_settextlinematrix(ctx->pgs, (gs_matrix *)&mat);
}
int pdfi_TD(pdf_context *ctx)
{
int code;
- pdf_num *Tx = NULL, *Ty = NULL;
+ double Txy[2];
gs_matrix m, mat;
- if (pdfi_count_stack(ctx) < 2) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
gs_make_identity(&m);
- Ty = (pdf_num *)ctx->stack_top[-1];
- Tx = (pdf_num *)ctx->stack_top[-2];
-
- if (Tx->type == PDF_INT) {
- m.tx = (float)Tx->value.i;
- } else {
- if (Tx->type == PDF_REAL) {
- m.tx = (float)Tx->value.d;
- } else {
- code = gs_note_error(gs_error_typecheck);
- goto TD_error;
- }
- }
+ code = pdfi_destack_reals(ctx, Txy, 2);
+ if (code < 0)
+ return code;
- if (Ty->type == PDF_INT) {
- m.ty = (float)Ty->value.i;
- } else {
- if (Ty->type == PDF_REAL) {
- m.ty = (float)Ty->value.d;
- } else {
- code = gs_note_error(gs_error_typecheck);
- goto TD_error;
- }
- }
+ m.tx = Txy[0];
+ m.ty = Txy[1];
if (ctx->text.BlockDepth == 0) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_TEXTOPNOBT, "pdfi_TD", NULL);
@@ -325,35 +258,26 @@ int pdfi_TD(pdf_context *ctx)
gs_make_identity(&mat);
code = gs_settextmatrix(ctx->pgs, &mat);
if (code < 0)
- goto TD_error;
+ return code;
code = gs_settextlinematrix(ctx->pgs, &mat);
if (code < 0)
- goto TD_error;
+ return code;
}
code = pdfi_set_TL(ctx, m.ty * 1.0f);
if (code < 0)
- goto TD_error;
+ return code;
code = gs_matrix_multiply(&m, &ctx->pgs->textlinematrix, &mat);
if (code < 0)
- goto TD_error;
+ return code;
code = gs_settextmatrix(ctx->pgs, (gs_matrix *)&mat);
if (code < 0)
- goto TD_error;
-
- code = gs_settextlinematrix(ctx->pgs, (gs_matrix *)&mat);
- if (code < 0)
- goto TD_error;
-
- pdfi_pop(ctx, 2);
- return code;
+ return code;
-TD_error:
- pdfi_pop(ctx, 2);
- return code;
+ return gs_settextlinematrix(ctx->pgs, (gs_matrix *)&mat);
}
/* This routine sets up most of the text params structure. In particular it
@@ -436,7 +360,7 @@ static int pdfi_show_set_params(pdf_context *ctx, pdf_string *s, gs_text_params_
for (i = 0;i < s->length; i++) {
/* Get the width (in unscaled text units) */
if (s->data[i] < current_font->FirstChar || s->data[i] > current_font->LastChar)
- width = 0;
+ width = current_font->MissingWidth;
else
width = current_font->Widths[s->data[i] - current_font->FirstChar];
/* And convert the width into an appropriate value for the current environment */
@@ -1083,8 +1007,10 @@ int pdfi_Tj(pdf_context *ctx)
goto exit;
s = (pdf_string *)ctx->stack_top[-1];
- if (s->type != PDF_STRING)
+ if (pdfi_type_of(s) != PDF_STRING) {
+ pdfi_pop(ctx, 1);
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
@@ -1198,7 +1124,7 @@ int pdfi_TJ(pdf_context *ctx)
goto exit;
a = (pdf_array *)ctx->stack_top[-1];
- if (a->type != PDF_ARRAY) {
+ if (pdfi_type_of(a) != PDF_ARRAY) {
pdfi_pop(ctx, 1);
return gs_note_error(gs_error_typecheck);
}
@@ -1260,29 +1186,17 @@ int pdfi_TJ(pdf_context *ctx)
if (code < 0)
goto TJ_error;
- if (o->type == PDF_INT) {
- dx = (double)((pdf_num *)o)->value.i / -1000;
+ if (pdfi_type_of(o) == PDF_STRING)
+ code = pdfi_show(ctx, (pdf_string *)o);
+ else {
+ code = pdfi_obj_to_real(ctx, o, &dx);
+ if (code < 0)
+ goto TJ_error;
+ dx /= -1000;
if (current_font->pfont && current_font->pfont->WMode == 0)
code = gs_rmoveto(ctx->pgs, dx, 0);
else
code = gs_rmoveto(ctx->pgs, 0, dx);
- if (code < 0)
- goto TJ_error;
- } else {
- if (o->type == PDF_REAL) {
- dx = ((pdf_num *)o)->value.d / -1000;
- if (current_font->pfont && current_font->pfont->WMode == 0)
- code = gs_rmoveto(ctx->pgs, dx, 0);
- else
- code = gs_rmoveto(ctx->pgs, 0, dx);
- if (code < 0)
- goto TJ_error;
- } else {
- if (o->type == PDF_STRING)
- code = pdfi_show(ctx, (pdf_string *)o);
- else
- code = gs_note_error(gs_error_typecheck);
- }
}
pdfi_countdown(o);
o = NULL;
@@ -1326,53 +1240,25 @@ static int pdfi_set_TL(pdf_context *ctx, double TL)
int pdfi_TL(pdf_context *ctx)
{
- int code = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ int code;
+ double d;
- n = (pdf_num *)ctx->stack_top[-1];
+ code = pdfi_destack_real(ctx, &d);
+ if (code < 0)
+ return code;
- if (n->type == PDF_INT)
- code = pdfi_set_TL(ctx, (double)(n->value.i * -1));
- else {
- if (n->type == PDF_REAL)
- code = pdfi_set_TL(ctx, n->value.d * -1.0);
- else
- code = gs_note_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ return pdfi_set_TL(ctx, -d);
}
int pdfi_Tm(pdf_context *ctx)
{
- int code = 0, i;
+ int code;
float m[6];
- pdf_num *n = NULL;
gs_matrix mat;
- if (pdfi_count_stack(ctx) < 6) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
- for (i = 1;i < 7;i++) {
- n = (pdf_num *)ctx->stack_top[-1 * i];
- if (n->type == PDF_INT)
- m[6 - i] = (float)n->value.i;
- else {
- if (n->type == PDF_REAL)
- m[6 - i] = (float)n->value.d;
- else {
- pdfi_pop(ctx, 6);
- return_error(gs_error_typecheck);
- }
- }
- }
- pdfi_pop(ctx, 6);
+ code = pdfi_destack_floats(ctx, m, 6);
+ if (code < 0)
+ return code;
if (ctx->text.BlockDepth == 0) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_TEXTOPNOBT, "pdfi_Tm", NULL);
@@ -1394,91 +1280,72 @@ int pdfi_Tm(pdf_context *ctx)
if (code < 0)
return code;
- code = gs_settextlinematrix(ctx->pgs, (gs_matrix *)&m);
-
- return code;
+ return gs_settextlinematrix(ctx->pgs, (gs_matrix *)&m);
}
int pdfi_Tr(pdf_context *ctx)
{
- int code = 0, mode = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
- n = (pdf_num *)ctx->stack_top[-1];
+ int code;
+ int64_t mode;
- if (n->type == PDF_INT)
- mode = n->value.i;
- else {
- if (n->type == PDF_REAL)
- mode = (int)n->value.d;
- else {
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
- }
- }
- pdfi_pop(ctx, 1);
+ code = pdfi_destack_int(ctx, &mode);
+ if (code < 0)
+ return code;
if (mode < 0 || mode > 7)
- code = gs_note_error(gs_error_rangecheck);
- else {
+ return_error(gs_error_rangecheck);
+
/* See comment regarding text rendering modes involving clip in pdfi_BT() above.
* The commented out code here will be needed when we enhance pdfwrite so that
* we don't need to do the clip separately.
*/
-/* if (!ctx->device_state.preserve_tr_mode) {*/
- gs_point initial_point;
+/*
+ if (ctx->device_state.preserve_tr_mode) {
+ gs_settextrenderingmode(ctx->pgs, mode);
+ } else
+*/
+ {
+ gs_point initial_point;
- /* Detect attempts to switch from a clipping mode to a non-clipping
- * mode, this is defined as invalid in the spec.
+ /* Detect attempts to switch from a clipping mode to a non-clipping
+ * mode, this is defined as invalid in the spec.
+ */
+ if (gs_currenttextrenderingmode(ctx->pgs) > 3 && mode < 4 && ctx->text.BlockDepth != 0)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BADTRSWITCH, "pdfi_Tr", NULL);
+
+ if (gs_currenttextrenderingmode(ctx->pgs) < 4 && mode >= 4 && ctx->text.BlockDepth != 0) {
+ /* If we are switching from a non-clip text rendering mode to a
+ * mode involving a cip, and we are already inside a text block,
+ * put a gsave in place so that we can accumulate a path for
+ * clipping without disturbing any existing path in the
+ * graphics state.
*/
- if (gs_currenttextrenderingmode(ctx->pgs) > 3 && mode < 4 && ctx->text.BlockDepth != 0)
- pdfi_set_warning(ctx, 0, NULL, W_PDF_BADTRSWITCH, "pdfi_Tr", NULL);
-
- if (gs_currenttextrenderingmode(ctx->pgs) < 4 && mode >= 4 && ctx->text.BlockDepth != 0) {
- /* If we are switching from a non-clip text rendering mode to a
- * mode involving a cip, and we are already inside a text block,
- * put a gsave in place so that we can accumulate a path for
- * clipping without disturbing any existing path in the
- * graphics state.
- */
- gs_settextrenderingmode(ctx->pgs, mode);
- pdfi_gsave(ctx);
- /* Capture the current position */
- code = gs_currentpoint(ctx->pgs, &initial_point);
- /* Start a new path (so our clip doesn't include any
- * already extant path in the graphics state)
- */
- gs_newpath(ctx->pgs);
- gs_moveto(ctx->pgs, initial_point.x, initial_point.y);
- }
- else {
- if (gs_currenttextrenderingmode(ctx->pgs) >= 4 && mode < 4 && ctx->text.BlockDepth != 0) {
- /* If we are switching from a clipping mode to a non-clipping
- * mode then behave as if we had an implicit ET to flush the
- * accumulated text to a clip, then set the text rendering mode
- * to the non-clip mode, and perform an implicit BT.
- */
- code = pdfi_ET(ctx);
- if (code < 0)
- return code;
- gs_settextrenderingmode(ctx->pgs, mode);
- code = pdfi_BT(ctx);
- if (code < 0)
- return code;
- }
- else
- gs_settextrenderingmode(ctx->pgs, mode);
- }
-/* }
+ gs_settextrenderingmode(ctx->pgs, mode);
+ pdfi_gsave(ctx);
+ /* Capture the current position */
+ code = gs_currentpoint(ctx->pgs, &initial_point);
+ /* Start a new path (so our clip doesn't include any
+ * already extant path in the graphics state)
+ */
+ gs_newpath(ctx->pgs);
+ gs_moveto(ctx->pgs, initial_point.x, initial_point.y);
+ } else if (gs_currenttextrenderingmode(ctx->pgs) >= 4 && mode < 4 && ctx->text.BlockDepth != 0) {
+ /* If we are switching from a clipping mode to a non-clipping
+ * mode then behave as if we had an implicit ET to flush the
+ * accumulated text to a clip, then set the text rendering mode
+ * to the non-clip mode, and perform an implicit BT.
+ */
+ code = pdfi_ET(ctx);
+ if (code < 0)
+ return code;
+ gs_settextrenderingmode(ctx->pgs, mode);
+ code = pdfi_BT(ctx);
+ if (code < 0)
+ return code;
+ }
else
- gs_settextrenderingmode(ctx->pgs, mode);*/
+ gs_settextrenderingmode(ctx->pgs, mode);
}
-
return code;
}
@@ -1489,26 +1356,14 @@ static int pdfi_set_Ts(pdf_context *ctx, double Ts)
int pdfi_Ts(pdf_context *ctx)
{
- int code = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ int code;
+ double d;
- n = (pdf_num *)ctx->stack_top[-1];
+ code = pdfi_destack_real(ctx, &d);
+ if (code < 0)
+ return code;
- if (n->type == PDF_INT)
- code = pdfi_set_Ts(ctx, (double)n->value.i);
- else {
- if (n->type == PDF_REAL)
- code = pdfi_set_Ts(ctx, n->value.d);
- else
- code = gs_note_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ return pdfi_set_Ts(ctx, d);
}
static int pdfi_set_Tw(pdf_context *ctx, double Tw)
@@ -1518,50 +1373,26 @@ static int pdfi_set_Tw(pdf_context *ctx, double Tw)
int pdfi_Tw(pdf_context *ctx)
{
- int code = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ int code;
+ double d;
- n = (pdf_num *)ctx->stack_top[-1];
+ code = pdfi_destack_real(ctx, &d);
+ if (code < 0)
+ return code;
- if (n->type == PDF_INT)
- code = pdfi_set_Tw(ctx, (double)n->value.i);
- else {
- if (n->type == PDF_REAL)
- code = pdfi_set_Tw(ctx, n->value.d);
- else
- code = gs_note_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ return pdfi_set_Tw(ctx, d);
}
int pdfi_Tz(pdf_context *ctx)
{
- int code = 0;
- pdf_num *n = NULL;
-
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
+ int code;
+ double d;
- n = (pdf_num *)ctx->stack_top[-1];
+ code = pdfi_destack_real(ctx, &d);
+ if (code < 0)
+ return code;
- if (n->type == PDF_INT)
- code = gs_settexthscaling(ctx->pgs, (double)n->value.i);
- else {
- if (n->type == PDF_REAL)
- code = gs_settexthscaling(ctx->pgs, n->value.d);
- else
- code = gs_note_error(gs_error_typecheck);
- }
- pdfi_pop(ctx, 1);
- return code;
+ return gs_settexthscaling(ctx->pgs, d);
}
int pdfi_singlequote(pdf_context *ctx)
@@ -1572,11 +1403,6 @@ int pdfi_singlequote(pdf_context *ctx)
pdfi_set_warning(ctx, 0, NULL, W_PDF_TEXTOPNOBT, "pdfi_singlequote", NULL);
}
- if (pdfi_count_stack(ctx) < 1) {
- pdfi_clearstack(ctx);
- return_error(gs_error_stackunderflow);
- }
-
code = pdfi_T_star(ctx);
if (code < 0)
return code;
@@ -1587,8 +1413,7 @@ int pdfi_singlequote(pdf_context *ctx)
int pdfi_doublequote(pdf_context *ctx)
{
int code;
- pdf_string *s;
- pdf_num *Tw, *Tc;
+ double Tw, Tc;
if (ctx->text.BlockDepth == 0) {
pdfi_set_warning(ctx, 0, NULL, W_PDF_TEXTOPNOBT, "pdfi_T_doublequote", NULL);
@@ -1599,38 +1424,35 @@ int pdfi_doublequote(pdf_context *ctx)
return_error(gs_error_stackunderflow);
}
- s = (pdf_string *)ctx->stack_top[-1];
- Tc = (pdf_num *)ctx->stack_top[-2];
- Tw = (pdf_num *)ctx->stack_top[-3];
- if (s->type != PDF_STRING || (Tc->type != PDF_INT && Tc->type != PDF_REAL) ||
- (Tw->type != PDF_INT && Tw->type != PDF_REAL)) {
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_STRING) {
pdfi_pop(ctx, 3);
return gs_note_error(gs_error_typecheck);
}
- if (Tc->type == PDF_INT)
- code = pdfi_set_Tc(ctx, (double)Tc->value.i);
- else
- code = pdfi_set_Tc(ctx, Tc->value.d);
- if (code < 0) {
- pdfi_pop(ctx, 3);
- return code;
- }
+ code = pdfi_obj_to_real(ctx, ctx->stack_top[-2], &Tc);
+ if (code < 0)
+ goto error;
+ code = pdfi_set_Tc(ctx, Tc);
+ if (code < 0)
+ goto error;
- if (Tw->type == PDF_INT)
- code = pdfi_set_Tw(ctx, (double)Tw->value.i);
- else
- code = pdfi_set_Tw(ctx, Tw->value.d);
- if (code < 0) {
- pdfi_pop(ctx, 3);
- return code;
- }
+ code = pdfi_obj_to_real(ctx, ctx->stack_top[-3], &Tw);
+ if (code < 0)
+ goto error;
+ code = pdfi_set_Tw(ctx, Tw);
+ if (code < 0)
+ goto error;
code = pdfi_T_star(ctx);
if (code < 0)
- return code;
+ goto error;
code = pdfi_Tj(ctx);
+ /* Tj pops one off the stack for us, leaving us 2 to go. */
+ pdfi_pop(ctx, 2);
+ return code;
+
+error:
pdfi_pop(ctx, 3);
return code;
}
diff --git a/pdf/pdf_tokens.h b/pdf/pdf_tokens.h
new file mode 100644
index 00000000..e9fe833d
--- /dev/null
+++ b/pdf/pdf_tokens.h
@@ -0,0 +1,116 @@
+/* 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 PARAM1
+#define PARAMCAT(A,B) A ## B
+#define PARAM1(A) PARAMCAT(TOKEN_, A),
+#define PARAM2(A,B) PARAMCAT(TOKEN_, B),
+#endif
+
+// Errors
+PARAM2("", NOT_A_KEYWORD)
+// Insert new error tokens here.
+PARAM2("", TOO_LONG)
+PARAM2("", INVALID_KEY)
+// Real tokens start here, at TOKEN_INVALID_KEY+1
+PARAM2("\"", QUOTE)
+PARAM2("'", APOSTROPHE)
+PARAM1(B)
+PARAM2("B*", Bstar)
+PARAM1(BDC)
+PARAM1(BI)
+PARAM1(BMC)
+PARAM1(BT)
+PARAM1(BX)
+PARAM1(CS)
+PARAM1(DP)
+PARAM1(Do)
+PARAM1(EI)
+PARAM1(EMC)
+PARAM1(ET)
+PARAM1(EX)
+PARAM1(F)
+PARAM1(G)
+PARAM1(ID)
+PARAM1(J)
+PARAM1(K)
+PARAM1(M)
+PARAM1(MP)
+PARAM1(Q)
+PARAM1(R)
+PARAM1(RG)
+PARAM1(S)
+PARAM1(SC)
+PARAM1(SCN)
+PARAM2("T*", Tstar)
+PARAM1(TD)
+PARAM1(TJ)
+PARAM1(TL)
+PARAM1(Tc)
+PARAM1(Td)
+PARAM1(Tf)
+PARAM1(Tj)
+PARAM1(Tm)
+PARAM1(Tr)
+PARAM1(Ts)
+PARAM1(Tw)
+PARAM1(Tz)
+PARAM1(W)
+PARAM2("W*", Wstar)
+PARAM1(b)
+PARAM2("b*", bstar)
+PARAM1(c)
+PARAM1(cm)
+PARAM1(cs)
+PARAM1(d)
+PARAM1(d0)
+PARAM1(d1)
+PARAM2("endobj", ENDOBJ)
+PARAM2("endstream", ENDSTREAM)
+PARAM1(f)
+PARAM2("f*", fstar)
+PARAM2("false", FALSE)
+PARAM1(g)
+PARAM1(gs)
+PARAM1(h)
+PARAM1(i)
+PARAM1(j)
+PARAM1(k)
+PARAM1(l)
+PARAM1(m)
+PARAM1(n)
+PARAM1(null)
+PARAM2("obj", OBJ)
+PARAM1(q)
+PARAM1(r)
+PARAM1(re)
+PARAM1(rg)
+PARAM1(ri)
+PARAM1(s)
+PARAM1(sc)
+PARAM1(scn)
+PARAM1(sh)
+PARAM2("startxref", STARTXREF)
+PARAM2("stream", STREAM)
+PARAM2("trailer", TRAILER)
+PARAM2("true", TRUE)
+PARAM1(v)
+PARAM1(w)
+PARAM2("xref", XREF)
+PARAM1(y)
+
+#undef PARAM1
+#undef PARAM2
+#undef PARAMCAT
diff --git a/pdf/pdf_trans.c b/pdf/pdf_trans.c
index df0194d7..fecb74c9 100644
--- a/pdf/pdf_trans.c
+++ b/pdf/pdf_trans.c
@@ -103,7 +103,7 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
double f;
gs_matrix save_matrix, GroupMat, group_Matrix;
gs_transparency_mask_subtype_t subtype = TRANSPARENCY_MASK_Luminosity;
- pdf_bool *Processed = NULL;
+ bool Processed, ProcessedKnown = 0;
bool save_OverrideICC = gs_currentoverrideicc(ctx->pgs);
#if DEBUG_TRANSPARENCY
@@ -114,28 +114,26 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
/* Following the logic of the ps code, cram a /Processed key in the SMask dict to
* track whether it's already been processed.
*/
- code = pdfi_dict_knownget_type(ctx, SMask, "Processed", PDF_BOOL, (pdf_obj **)&Processed);
- if (code > 0 && Processed->value) {
+ code = pdfi_dict_knownget_bool(ctx, SMask, "Processed", &Processed);
+ if (code > 0) {
+ if (Processed) {
#if DEBUG_TRANSPARENCY
- dbgmprintf(ctx->memory, "SMask already built, skipping\n");
+ dbgmprintf(ctx->memory, "SMask already built, skipping\n");
#endif
- goto exit;
+ code = 0;
+ goto exit;
+ }
+ ProcessedKnown = 1;
}
gs_setoverrideicc(ctx->pgs, true);
/* If /Processed not in the dict, put it there */
if (code == 0) {
- /* the cleanup at end of this routine assumes Processed has a ref */
- code = pdfi_object_alloc(ctx, PDF_BOOL, 0, (pdf_obj **)&Processed);
- if (code < 0)
- goto exit;
- Processed->value = false;
- /* pdfi_object_alloc() doesn't grab a ref */
- pdfi_countup(Processed);
- code = pdfi_dict_put(ctx, SMask, "Processed", (pdf_obj *)Processed);
+ code = pdfi_dict_put_bool(ctx, SMask, "Processed", false);
if (code < 0)
goto exit;
+ ProcessedKnown = 1;
}
/* See pdf1.7 pg 553 (pain in the butt to find this!) */
@@ -172,21 +170,25 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
/* TR is transfer function (Optional) */
code = pdfi_dict_knownget(ctx, SMask, "TR", (pdf_obj **)&TR);
if (code > 0) {
- if (TR->type == PDF_DICT || TR->type == PDF_STREAM) {
- 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");
- }
- } else {
- dmprintf(ctx->memory, "WARNING: Ignoring invalid TR in SMask\n");
+ switch (pdfi_type_of(TR)) {
+ case PDF_DICT:
+ case PDF_STREAM:
+ 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");
+ }
+ break;
+ case PDF_NAME:
+ if (!pdfi_name_is((pdf_name *)TR, "Identity")) {
+ dmprintf(ctx->memory, "WARNING: Unknown TR in SMask\n");
+ }
+ break;
+ default:
+ dmprintf(ctx->memory, "WARNING: Ignoring invalid TR in SMask\n");
}
}
@@ -251,8 +253,14 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
if (code > 0) {
/* TODO: Stuff with colorspace, see .execmaskgroup */
code = pdfi_dict_knownget(ctx, Group, "CS", &CS);
- if (code < 0)
- goto exit;
+ if (code < 0) {
+ code = pdfi_dict_knownget(ctx, Group, "ColorSpace", &CS);
+ if (code < 0) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_GROUP_NO_CS, "pdfi_trans_set_mask", (char *)"*** Defaulting to currrent colour space");
+ goto exit;
+ }
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_GROUP_HAS_COLORSPACE, "pdfi_trans_set_mask", NULL);
+ }
if (code > 0) {
code = pdfi_create_colorspace(ctx, CS, (pdf_dict *)ctx->main_stream,
ctx->page.CurrentPageDict, &pcs, false);
@@ -284,6 +292,9 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
}
params.Background_components = pdfi_array_size(BC);
+ if (gs_color_space_num_components(params.ColorSpace) != params.Background_components)
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_GROUP_BAD_BC, "pdfi_trans_set_mask", NULL);
+
/* TODO: Not sure how to handle this... recheck PS code (pdf_draw.ps/gssmask) */
/* This should be "currentgray" for the color that we put in params.ColorSpace,
* It looks super-convoluted to actually get this value. Really?
@@ -300,7 +311,7 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
code = pdfi_form_execgroup(ctx, ctx->page.CurrentPageDict, G_stream,
igs->GroupGState, NULL, &group_Matrix);
code1 = gs_end_transparency_mask(ctx->pgs, colorindex);
- if (code != 0)
+ if (code == 0)
code = code1;
/* Put back the matrix (we couldn't just rely on gsave/grestore for whatever reason,
@@ -309,8 +320,12 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
gs_setmatrix(ctx->pgs, &save_matrix);
/* Set Processed flag */
- if (code == 0 && Processed)
- Processed->value = true;
+ if (code == 0 && ProcessedKnown)
+ {
+ code = pdfi_dict_put_bool(ctx, SMask, "Processed", true);
+ if (code < 0)
+ goto exit;
+ }
} else {
/* take action on a non-/Mask entry. What does this mean ? What do we need to do */
dmprintf(ctx->memory, "Warning: Type is not /Mask, entry ignored in pdfi_set_trans_mask\n");
@@ -332,7 +347,6 @@ static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int color
pdfi_countdown(BBox);
pdfi_countdown(Matrix);
pdfi_countdown(CS);
- pdfi_countdown(Processed);
#if DEBUG_TRANSPARENCY
dbgmprintf(ctx->memory, "pdfi_trans_set_mask (.execmaskgroup) END\n");
#endif
@@ -393,7 +407,7 @@ static int pdfi_transparency_group_common(pdf_context *ctx, pdf_dict *page_dict,
/* Didn't find a /CS key, try again using /ColorSpace */
code = pdfi_dict_knownget(ctx, group_dict, "ColorSpace", &CS);
}
- if (code > 0 && CS->type != PDF_NULL) {
+ if (code > 0 && pdfi_type_of(CS) != PDF_NULL) {
code = pdfi_setcolorspace(ctx, CS, group_dict, page_dict);
if (code < 0)
goto exit;
@@ -865,6 +879,7 @@ int pdfi_trans_teardown(pdf_context *ctx, pdfi_trans_state_t *state)
int pdfi_trans_set_params(pdf_context *ctx)
{
+ int code = 0;
pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
gs_transparency_channel_selector_t csel;
@@ -874,9 +889,9 @@ int pdfi_trans_set_params(pdf_context *ctx)
else
csel = TRANSPARENCY_CHANNEL_Opacity;
if (igs->SMask) {
- pdfi_trans_set_mask(ctx, igs, csel);
+ code = pdfi_trans_set_mask(ctx, igs, csel);
}
}
- return 0;
+ return code;
}
diff --git a/pdf/pdf_types.h b/pdf/pdf_types.h
index b8213e0b..6f78dde7 100644
--- a/pdf/pdf_types.h
+++ b/pdf/pdf_types.h
@@ -47,6 +47,7 @@ typedef enum pdf_obj_type_e {
PDF_INDIRECT = 'R',
PDF_BOOL = 'b',
PDF_KEYWORD = 'K',
+ PDF_FAST_KEYWORD = 'k',
PDF_FONT = 'F',
PDF_STREAM = 'S',
/* The following aren't PDF object types, but are objects we either want to
@@ -57,6 +58,7 @@ typedef enum pdf_obj_type_e {
PDF_DICT_MARK = '<',
PDF_PROC_MARK = '{',
PDF_CMAP = 'C',
+ PDF_BUFFER = 'B',
/* 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
@@ -115,11 +117,6 @@ typedef struct pdf_obj_s {
pdf_obj_common;
} pdf_obj;
-typedef struct pdf_bool_s {
- pdf_obj_common;
- bool value;
-} pdf_bool;
-
typedef struct pdf_num_s {
pdf_obj_common;
union {
@@ -141,22 +138,29 @@ typedef struct pdf_name_s {
unsigned char data[PDF_NAME_DECLARED_LENGTH];
} pdf_name;
+/* For storing arbitrary byte arrays where the length may be
+ greater than PDF_NAME_DECLARED_LENGTH - prevents static
+ alalysis tools complaining if we just used pdf_string
+ */
+typedef struct pdf_buffer_s {
+ pdf_obj_common;
+ uint32_t length;
+ unsigned char *data;
+} pdf_buffer;
+
typedef enum pdf_key_e {
- TOKEN_NOT_A_KEYWORD,
- TOKEN_OBJ,
- TOKEN_ENDOBJ,
- TOKEN_STREAM,
- TOKEN_ENDSTREAM,
- TOKEN_XREF,
- TOKEN_STARTXREF,
- TOKEN_TRAILER,
- TOKEN_INVALID_KEY,
+#include "pdf_tokens.h"
+ TOKEN__LAST_KEY,
} pdf_key;
+#define PDF_NULL_OBJ ((pdf_obj *)(uintptr_t)TOKEN_null)
+#define PDF_TRUE_OBJ ((pdf_obj *)(uintptr_t)TOKEN_TRUE)
+#define PDF_FALSE_OBJ ((pdf_obj *)(uintptr_t)TOKEN_FALSE)
+#define PDF_TOKEN_AS_OBJ(token) ((pdf_obj *)(uintptr_t)(token))
+
typedef struct pdf_keyword_s {
pdf_obj_common;
uint32_t length;
- pdf_key key;
unsigned char data[PDF_NAME_DECLARED_LENGTH];
} pdf_keyword;
@@ -251,4 +255,29 @@ typedef struct pdf_c_stream_s {
char unget_buffer[UNREAD_BUFFER_SIZE];
} pdf_c_stream;
+#ifndef inline
+#define inline __inline
+#endif /* inline */
+
+#define pdfi_type_of(A) pdfi_type_of_imp((pdf_obj *)A)
+
+static inline pdf_obj_type pdfi_type_of_imp(pdf_obj *obj)
+{
+ if ((uintptr_t)obj > TOKEN__LAST_KEY)
+ return obj->type;
+ else if ((uintptr_t)obj == TOKEN_TRUE || (uintptr_t)obj == TOKEN_FALSE)
+ return PDF_BOOL;
+ else if ((uintptr_t)obj == TOKEN_null)
+ return PDF_NULL;
+ else
+ return PDF_FAST_KEYWORD;
+}
+
+static inline int pdf_object_num(pdf_obj *obj)
+{
+ if ((uintptr_t)obj > TOKEN__LAST_KEY)
+ return obj->object_num;
+ return 0;
+}
+
#endif
diff --git a/pdf/pdf_warnings.h b/pdf/pdf_warnings.h
index 21b2403f..82928bef 100644
--- a/pdf/pdf_warnings.h
+++ b/pdf/pdf_warnings.h
@@ -18,6 +18,9 @@
#endif
PARAM(W_PDF_NOWARNING, "no warning"),
PARAM(W_PDF_BAD_XREF_SIZE, "incorrect xref size"),
+PARAM(W_PDF_BAD_XREF_ENTRY_SIZE, "xref entry not exactly 20 bytes"),
+PARAM(W_PDF_BAD_XREF_ENTRY_NO_EOL, "xref entry not terminated with EOL"),
+PARAM(W_PDF_BAD_XREF_ENTRY_FORMAT, "xref entry not valid format"),
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"),
@@ -43,6 +46,7 @@ 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_STREAM_BAD_KEYWORD, "A stream keyword was not terminated with a linefeed (0x0A)"),
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"),
@@ -58,5 +62,10 @@ PARAM(W_PDF_CA_OUTOFRANGE, "CA or ca value not in range 0.0 to 1.0, cla
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"),
-
+PARAM(W_PDF_GROUP_HAS_COLORSPACE, "Group attributes dictionary has /ColorSpace instead of /CS"),
+PARAM(W_PDF_GROUP_BAD_BC, "Group attributes dictionary /BC differs in number of components from the colour space"),
+PARAM(W_PDF_INT_AS_REAL, "found real number when expecting int"),
+PARAM(PDF_W_NO_TREE_LIMITS, "Name tree node missing required Limits entry"),
+PARAM(PDF_W_BAD_TREE_LIMITS, "Name tree node Limits array does not have 2 entries"),
+PARAM(PDF_W_NAMES_ARRAY_SIZE, "Name tree Names array size not a mulitple of 2"),
#undef PARAM
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index 7e611130..3f3d8008 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -141,7 +141,7 @@ static int read_xref_stream_entries(pdf_context *ctx, pdf_c_stream *s, uint64_t
/* Forward definition */
static int read_xref(pdf_context *ctx, pdf_c_stream *s);
/* These two routines are recursive.... */
-static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s);
+static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s, int obj_num);
static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *s)
{
@@ -153,9 +153,10 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
int64_t size;
int64_t num;
int64_t W[3];
+ int objnum;
bool known = false;
- if (stream_obj->type != PDF_STREAM)
+ if (pdfi_type_of(stream_obj) != PDF_STREAM)
return_error(gs_error_typecheck);
code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &sdict);
@@ -307,7 +308,7 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
return code;
}
} else {
- int64_t start, end;
+ int64_t start, size;
if (code < 0) {
pdfi_close_file(ctx, XRefStrm);
@@ -334,7 +335,7 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
return code;
}
- code = pdfi_array_get_int(ctx, a, (uint64_t)i+1, &end);
+ code = pdfi_array_get_int(ctx, a, (uint64_t)i+1, &size);
if (code < 0) {
pdfi_countdown(a);
pdfi_close_file(ctx, XRefStrm);
@@ -343,8 +344,11 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
return code;
}
- if (start + end >= ctx->xref_table->xref_size) {
- code = resize_xref(ctx, start + end);
+ if (size < 1)
+ continue;
+
+ if (start + size >= ctx->xref_table->xref_size) {
+ code = resize_xref(ctx, start + size);
if (code < 0) {
pdfi_countdown(a);
pdfi_close_file(ctx, XRefStrm);
@@ -354,7 +358,7 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
}
}
- code = read_xref_stream_entries(ctx, XRefStrm, start, start + end - 1, (uint64_t *)W);
+ code = read_xref_stream_entries(ctx, XRefStrm, start, start + size - 1, (uint64_t *)W);
if (code < 0) {
pdfi_countdown(a);
pdfi_close_file(ctx, XRefStrm);
@@ -391,145 +395,106 @@ static int pdfi_process_xref_stream(pdf_context *ctx, pdf_stream *stream_obj, pd
pdfi_seek(ctx, s, num, SEEK_SET);
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &objnum);
+ if (code == 1)
+ return pdfi_read_xref_stream_dict(ctx, s, objnum);
+
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
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 */
- pdfi_pop(ctx, 1);
- return(read_xref(ctx, ctx->main_stream));
- } else
- code = pdfi_read_xref_stream_dict(ctx, s);
-
- return code;
+ if (code == TOKEN_XREF) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_PREV_NOT_XREF_STREAM, "pdfi_process_xref_stream", NULL);
+ if (!ctx->args.pdfstoponerror)
+ /* Read old-style xref table */
+ return(read_xref(ctx, ctx->main_stream));
+ }
+ return_error(gs_error_syntaxerror);
}
-static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s)
+static int pdfi_read_xref_stream_dict(pdf_context *ctx, pdf_c_stream *s, int obj_num)
{
int code;
+ int gen_num;
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "\n%% Reading PDF 1.5+ xref stream\n");
- if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_INT) {
- /* 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)
- return(pdfi_repair_file(ctx));
+ /* We have the obj_num. Lets try for obj_num gen obj as a XRef stream */
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &gen_num);
+ if (code <= 0)
+ return(pdfi_repair_file(ctx));
- if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_INT) {
- /* Second element is not an integer, not a valid xref */
- pdfi_pop(ctx, 1);
- return(pdfi_repair_file(ctx));
- }
+ /* Try to read 'obj' */
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
+ if (code < 0)
+ return code;
+ if (code == 0)
+ return_error(gs_error_syntaxerror);
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0) {
- pdfi_pop(ctx, 1);
- return code;
- }
- if (code == 0) {
- pdfi_pop(ctx, 1);
- return_error(gs_error_syntaxerror);
- }
+ /* Third element must be obj, or it's not a valid xref */
+ if (code != TOKEN_OBJ)
+ return(pdfi_repair_file(ctx));
- if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_KEYWORD) {
- /* Second element is not an integer, not a valid xref */
- pdfi_pop(ctx, 2);
- return(pdfi_repair_file(ctx));
- } else {
- int obj_num, gen_num;
+ do {
+ code = pdfi_read_token(ctx, ctx->main_stream, obj_num, gen_num);
+ if (code <= 0)
+ return pdfi_repair_file(ctx);
- pdf_keyword *keyword = (pdf_keyword *)ctx->stack_top[-1];
+ if (pdfi_count_stack(ctx) >= 2 && pdfi_type_of(ctx->stack_top[-1]) == PDF_FAST_KEYWORD) {
+ uintptr_t keyword = (uintptr_t)ctx->stack_top[-1];
+ if (keyword == TOKEN_STREAM) {
+ pdf_dict *dict;
+ pdf_stream *sdict = NULL;
+ int64_t Length;
- if (keyword->key != TOKEN_OBJ) {
- pdfi_pop(ctx, 3);
- return(pdfi_repair_file(ctx));
- }
- /* pop the 'obj', generation and object numbers */
- pdfi_pop(ctx, 1);
- gen_num = ((pdf_num *)ctx->stack_top[-1])->value.i;
- pdfi_pop(ctx, 1);
- obj_num = ((pdf_num *)ctx->stack_top[-1])->value.i;
- pdfi_pop(ctx, 1);
+ /* Remove the 'stream' token from the stack, should leave a dictionary object on the stack */
+ pdfi_pop(ctx, 1);
+ if (pdfi_type_of(ctx->stack_top[-1]) != PDF_DICT) {
+ return pdfi_repair_file(ctx);
+ }
+ dict = (pdf_dict *)ctx->stack_top[-1];
- do {
- code = pdfi_read_token(ctx, ctx->main_stream, obj_num, gen_num);
- if (code <= 0)
+ /* Convert the dict into a stream (sdict comes back with at least one ref) */
+ code = pdfi_obj_dict_to_stream(ctx, dict, &sdict, true);
+ /* Pop off the dict */
+ pdfi_pop(ctx, 1);
+ if (code < 0) {
+ /* TODO: should I return code instead of trying to repair?
+ * Normally the above routine should not fail so something is
+ * probably seriously fubar.
+ */
return pdfi_repair_file(ctx);
+ }
+ dict = NULL;
+
+ /* Init the stuff for the stream */
+ sdict->stream_offset = pdfi_unread_tell(ctx);
+ sdict->object_num = obj_num;
+ sdict->generation_num = gen_num;
+
+ code = pdfi_dict_get_int(ctx, sdict->stream_dict, "Length", &Length);
+ if (code < 0) {
+ /* TODO: Not positive this will actually have a length -- just use 0 */
+ pdfi_set_error_var(ctx, 0, NULL, E_PDF_BADSTREAM, "pdfi_read_xref_stream_dict", "Xref Stream object %u missing mandatory keyword /Length\n", obj_num);
+ code = 0;
+ Length = 0;
+ }
+ sdict->Length = Length;
+ sdict->length_valid = true;
- 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;
- pdf_stream *sdict = NULL;
- int64_t Length;
-
- /* Remove the 'stream' token from the stack, should leave a dictionary object on the stack */
- pdfi_pop(ctx, 1);
- if (((pdf_obj *)ctx->stack_top[-1])->type != PDF_DICT) {
- pdfi_pop(ctx, 1);
- return pdfi_repair_file(ctx);
- }
- dict = (pdf_dict *)ctx->stack_top[-1];
-
- /* Convert the dict into a stream (sdict comes back with at least one ref) */
- code = pdfi_obj_dict_to_stream(ctx, dict, &sdict, true);
- if (code < 0) {
- pdfi_pop(ctx, 1);
- /* TODO: should I return code instead of trying to repair?
- * Normally the above routine should not fail so something is
- * probably seriously fubar.
- */
- return pdfi_repair_file(ctx);
- }
- /* Pop off the dict */
- pdfi_pop(ctx, 1);
- dict = NULL;
-
- /* Init the stuff for the stream */
- sdict->stream_offset = pdfi_unread_tell(ctx);
- sdict->object_num = obj_num;
- sdict->generation_num = gen_num;
-
- code = pdfi_dict_get_int(ctx, sdict->stream_dict, "Length", &Length);
- if (code < 0) {
- /* TODO: Not positive this will actually have a length -- just use 0 */
- char extra_info[gp_file_name_sizeof];
-
- 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;
- }
- sdict->Length = Length;
- sdict->length_valid = true;
-
- code = pdfi_process_xref_stream(ctx, sdict, ctx->main_stream);
- if (code < 0) {
- pdfi_countdown(sdict);
- return (pdfi_repair_file(ctx));
- }
- pdfi_countdown(sdict);
- break;
- }
- if (keyword->key == TOKEN_ENDOBJ) {
- /* Something went wrong, this is not a stream dictionary */
- pdfi_pop(ctx, 3);
- return(pdfi_repair_file(ctx));
- break;
- }
+ code = pdfi_process_xref_stream(ctx, sdict, ctx->main_stream);
+ if (code < 0) {
+ pdfi_countdown(sdict);
+ return (pdfi_repair_file(ctx));
}
- } while(1);
+ pdfi_countdown(sdict);
+ break;
+ } else if (keyword == TOKEN_ENDOBJ) {
+ /* Something went wrong, this is not a stream dictionary */
+ return(pdfi_repair_file(ctx));
+ }
}
- } else {
- /* Not an 'xref' and not an integer, so not a valid xref */
- return(pdfi_repair_file(ctx));
- }
+ } while(1);
return 0;
}
@@ -676,8 +641,8 @@ static int write_offset(byte *B, gs_offset_t o, unsigned int g, unsigned char fr
static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *section_start, uint64_t *section_size)
{
int code = 0, i, j;
- pdf_obj *o = NULL;
- uint64_t start = 0, size = 0;
+ int start = 0;
+ int size = 0;
int64_t bytes = 0;
char Buffer[21];
@@ -686,57 +651,37 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
if (ctx->args.pdfdebug)
dmprintf(ctx->memory, "\n%% Reading xref section\n");
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
-
- if (code < 0)
- return code;
-
- if (pdfi_count_stack(ctx) < 1)
- return_error(gs_error_stackunderflow);
-
- o = ctx->stack_top[-1];
- if (o->type == PDF_KEYWORD)
- return 0;
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &start);
+ if (code < 0) {
+ /* Not an int, might be a keyword */
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
+ if (code < 0)
+ return code;
- if (o->type != PDF_INT) {
- /* element is not an integer, not a valid xref */
- pdfi_pop(ctx, 1);
- return_error(gs_error_typecheck);
+ if (code != TOKEN_TRAILER) {
+ /* element is not an integer, and not a keyword - not a valid xref */
+ return_error(gs_error_typecheck);
+ }
+ return 1;
}
- if (((pdf_num *)o)->value.i < 0) {
- pdfi_pop(ctx, 1);
+ if (start < 0)
return_error(gs_error_rangecheck);
- }
- *section_start = start = ((pdf_num *)o)->value.i;
+ *section_start = start;
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0) {
- pdfi_pop(ctx, 1);
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &size);
+ if (code < 0)
return code;
- }
- if (code == 0) {
- pdfi_pop(ctx, 1);
+ if (code == 0)
return_error(gs_error_syntaxerror);
- }
-
- o = ctx->stack_top[-1];
- if (o->type != PDF_INT) {
- /* element is not an integer, not a valid xref */
- 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);
+ if (size < 0)
return_error(gs_error_rangecheck);
- }
- *section_size = size = ((pdf_num *)o)->value.i;
- pdfi_pop(ctx, 2);
+ *section_size = size;
if (ctx->args.pdfdebug)
dmprintf2(ctx->memory, "\n%% Section starts at %d and has %d entries\n", (unsigned int) start, (unsigned int)size);
@@ -784,9 +729,12 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
if (bytes < 20)
return_error(gs_error_ioerror);
j = 19;
+ if ((Buffer[19] != 0x0a && Buffer[19] != 0x0d) || (Buffer[18] != 0x0d && Buffer[18] != 0x0a && Buffer[18] != 0x20))
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_XREF_ENTRY_SIZE, "read_xref_section", NULL);
while (Buffer[j] != 0x0D && Buffer[j] != 0x0A) {
pdfi_unread_byte(ctx, s, (byte)Buffer[j]);
if (--j < 0) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_XREF_ENTRY_NO_EOL, "read_xref_section", NULL);
dmprintf(ctx->memory, "Invalid xref entry, line terminator missing.\n");
code = read_xref_entry_slow(ctx, s, &off, &gen, &free);
if (code < 0)
@@ -803,6 +751,7 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
continue;
if (sscanf(Buffer, "%"PRIdOFFSET" %d %c", &entry->u.uncompressed.offset, &entry->u.uncompressed.generation_num, &free) != 3) {
+ pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_XREF_ENTRY_FORMAT, "read_xref_section", NULL);
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);
@@ -827,16 +776,17 @@ static int read_xref_section(pdf_context *ctx, pdf_c_stream *s, uint64_t *sectio
static int read_xref(pdf_context *ctx, pdf_c_stream *s)
{
int code = 0;
- pdf_obj **o = NULL;
- pdf_keyword *k;
pdf_dict *d = NULL;
uint64_t size = 0, max_obj = 0;
int64_t num;
+ int obj_num;
+
+ if (ctx->repaired)
+ return 0;
do {
uint64_t section_start, section_size;
- o = ctx->stack_top;
code = read_xref_section(ctx, s, &section_start, &section_size);
if (code < 0)
return code;
@@ -844,23 +794,15 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
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];
- if(k->type != PDF_KEYWORD || k->key != TOKEN_TRAILER)
- return_error(gs_error_syntaxerror);
- else {
- pdfi_pop(ctx, 1);
- break;
- }
- }
- } while (1);
+ /* code == 1 => read_xref_section ended with a trailer. */
+ } while (code != 1);
code = pdfi_read_dict(ctx, ctx->main_stream, 0, 0);
if (code < 0)
return code;
d = (pdf_dict *)ctx->stack_top[-1];
- if (d->type != PDF_DICT) {
+ if (pdfi_type_of(d) != PDF_DICT) {
pdfi_pop(ctx, 1);
return_error(gs_error_typecheck);
}
@@ -950,21 +892,25 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
}
}
- pdfi_loop_detector_mark(ctx);
+ code = pdfi_loop_detector_mark(ctx);
+ if (code < 0) {
+ pdfi_pop(ctx, 1);
+ return code;
+ }
/* Because of the way the code works when we read a file which is a pure
* xref stream file, we need to read the first integer of 'x y obj'
* because the xref stream decoding code expects that to be on the stack.
*/
pdfi_seek(ctx, s, num, SEEK_SET);
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &obj_num);
if (code < 0) {
pdfi_loop_detector_cleartomark(ctx);
pdfi_pop(ctx, 1);
return code;
}
- code = pdfi_read_xref_stream_dict(ctx, ctx->main_stream);
+ code = pdfi_read_xref_stream_dict(ctx, ctx->main_stream, obj_num);
if (code < 0) {
pdfi_loop_detector_cleartomark(ctx);
pdfi_pop(ctx, 1);
@@ -1017,13 +963,16 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
if (code < 0)
return code;
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0)
- return(code);
- if (code == 0)
+ if (!ctx->repaired) {
+ code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
+ if (code < 0)
+ return(code);
+ if (code == 0)
return_error(gs_error_syntaxerror);
+ } else
+ return 0;
- if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD && ((pdf_keyword *)ctx->stack_top[-1])->key == TOKEN_XREF) {
+ if ((intptr_t)(ctx->stack_top[-1]) == (intptr_t)TOKEN_XREF) {
/* Read old-style xref table */
pdfi_pop(ctx, 1);
return(read_xref(ctx, ctx->main_stream));
@@ -1036,61 +985,51 @@ static int read_xref(pdf_context *ctx, pdf_c_stream *s)
int pdfi_read_xref(pdf_context *ctx)
{
int code = 0;
- bool do_repair = false;
+ int obj_num;
code = pdfi_loop_detector_mark(ctx);
if (code < 0)
return code;
- if (ctx->startxref != 0) {
- code = pdfi_loop_detector_add_object(ctx, ctx->startxref);
- if (code < 0)
- goto exit;
+ if (ctx->startxref == 0)
+ goto repair;
- if (ctx->args.pdfdebug)
- dmprintf(ctx->memory, "%% Trying to read 'xref' token for xref table, or 'int int obj' for an xref stream\n");
+ code = pdfi_loop_detector_add_object(ctx, ctx->startxref);
+ if (code < 0)
+ goto exit;
- if (ctx->startxref > ctx->main_stream_length - 5) {
- pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTARTXREF, "pdfi_read_xref", (char *)"startxref offset is beyond end of file");
- do_repair = true;
- goto exit;
- }
+ if (ctx->args.pdfdebug)
+ dmprintf(ctx->memory, "%% Trying to read 'xref' token for xref table, or 'int int obj' for an xref stream\n");
+ if (ctx->startxref > ctx->main_stream_length - 5) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTARTXREF, "pdfi_read_xref", (char *)"startxref offset is beyond end of file");
+ goto repair;
+ }
+ if (ctx->startxref < 0) {
+ pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTARTXREF, "pdfi_read_xref", (char *)"startxref offset is before start of file");
+ goto repair;
+ }
- /* Read the xref(s) */
- pdfi_seek(ctx, ctx->main_stream, ctx->startxref, SEEK_SET);
+ /* Read the xref(s) */
+ pdfi_seek(ctx, ctx->main_stream, ctx->startxref, SEEK_SET);
- code = pdfi_read_token(ctx, ctx->main_stream, 0, 0);
- if (code < 0) {
+ /* If it starts with an int, it's an xref stream dict */
+ code = pdfi_read_bare_int(ctx, ctx->main_stream, &obj_num);
+ if (code == 1) {
+ code = pdfi_read_xref_stream_dict(ctx, ctx->main_stream, obj_num);
+ if (code < 0)
+ goto repair;
+ } else {
+ /* If not, it had better start 'xref', and be an old-style xref table */
+ code = pdfi_read_bare_keyword(ctx, ctx->main_stream);
+ if (code != TOKEN_XREF) {
pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTARTXREF, "pdfi_read_xref", (char *)"Failed to read any token at the startxref location");
- do_repair = true;
- goto exit;
- }
-
- if (pdfi_count_stack(ctx) < 1) {
- code = gs_note_error(gs_error_undefined);
- goto exit;
+ goto repair;
}
- if (((pdf_obj *)ctx->stack_top[-1])->type == PDF_KEYWORD && ((pdf_keyword *)ctx->stack_top[-1])->key == TOKEN_XREF) {
- /* Read old-style xref table */
- pdfi_pop(ctx, 1);
- code = read_xref(ctx, ctx->main_stream);
- if (code < 0) {
- do_repair = true;
- goto exit;
- }
- } else {
- code = pdfi_read_xref_stream_dict(ctx, ctx->main_stream);
- if (code < 0){
- do_repair = true;
- goto exit;
- }
- }
- } else {
- /* Attempt to repair PDF file */
- do_repair = true;
- goto exit;
+ code = read_xref(ctx, ctx->main_stream);
+ if (code < 0)
+ goto repair;
}
if(ctx->args.pdfdebug && ctx->xref_table) {
@@ -1159,11 +1098,15 @@ int pdfi_read_xref(pdf_context *ctx)
exit:
(void)pdfi_loop_detector_cleartomark(ctx);
- if (do_repair)
- return(pdfi_repair_file(ctx));
if (code < 0)
return code;
return 0;
+
+repair:
+ (void)pdfi_loop_detector_cleartomark(ctx);
+ if (!ctx->repaired)
+ return(pdfi_repair_file(ctx));
+ return 0;
}
diff --git a/pdf/pdftop.c b/pdf/pdftop.c
index 5e147cdd..9f5cfdf4 100644
--- a/pdf/pdftop.c
+++ b/pdf/pdftop.c
@@ -60,9 +60,9 @@ extern const char gp_file_name_list_separator;
static int
pdf_detect_language(const char *s, int len)
{
- if (len < 5)
- return 1;
- return memcmp(s, "%!PDF", 5);
+ if (len >= 5 && memcmp(s, "%!PDF", 5) == 0)
+ return 100;
+ return 0;
}
static const pl_interp_characteristics_t *
@@ -393,7 +393,7 @@ static int plist_value_get_int64(gs_param_typed_value *pvalue, int64_t *pint)
/* Get the value for a string or a name (null terminated) */
static int plist_value_get_string_or_name(pdf_context *ctx, gs_param_typed_value *pvalue,
- char **pstr, int *plen)
+ char **pstr, int *plen, bool *is_name)
{
const byte *data;
uint size;
@@ -401,9 +401,11 @@ static int plist_value_get_string_or_name(pdf_context *ctx, gs_param_typed_value
if (pvalue->type == gs_param_type_string) {
data = pvalue->value.s.data;
size = pvalue->value.s.size;
+ *is_name = false;
} else if (pvalue->type == gs_param_type_name) {
data = pvalue->value.n.data;
size = pvalue->value.n.size;
+ *is_name = true;
} else {
return_error(gs_error_typecheck);
}
@@ -481,6 +483,7 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
gs_param_key_t key;
int code;
int len;
+ bool discard_isname;
param_init_enumerator(&enumerator);
if ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
@@ -645,7 +648,7 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
return code;
}
if (!strncmp(param, "PDFPassword", 11)) {
- code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->encryption.Password , &ctx->encryption.PasswordLen);
+ code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->encryption.Password , &ctx->encryption.PasswordLen, &discard_isname);
if (code < 0)
return code;
}
@@ -671,14 +674,14 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
return code;
}
if (!strncmp(param, "UseOutputIntent", strlen("UseOutputIntent"))) {
- code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->args.UseOutputIntent, &len);
+ code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->args.UseOutputIntent, &len, &discard_isname);
if (code < 0)
return code;
}
if (!strncmp(param, "FONTPATH", 11)) {
char *s = NULL;
int slen;
- code = plist_value_get_string_or_name(ctx, &pvalue, &s , &slen);
+ code = plist_value_get_string_or_name(ctx, &pvalue, &s , &slen, &discard_isname);
if (code < 0)
return code;
code = pdfi_add_paths_to_search_paths(ctx, (const char *)s, slen, true);
@@ -687,19 +690,24 @@ pdf_impl_set_param(pl_interp_implementation_t *impl,
if (!strncmp(param, "FONTMAP", 7)) {
char *s = NULL;
int slen;
- code = plist_value_get_string_or_name(ctx, &pvalue, &s, &slen);
+ code = plist_value_get_string_or_name(ctx, &pvalue, &s, &slen, &discard_isname);
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);
+ code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidfsubstpath.data, (int *)&ctx->args.cidfsubstpath.size, &discard_isname);
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);
+ code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidfsubstfont.data, (int *)&ctx->args.cidfsubstfont.size, &discard_isname);
+ if (code < 0)
+ return code;
+ }
+ if (!strncmp(param, "SUBSTFONT", 12)) {
+ code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.defaultfont.data, (int *)&ctx->args.defaultfont.size, &ctx->args.defaultfont_is_name);
if (code < 0)
return code;
}