summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdf-x/xsrc/pdfobj.c
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2013-09-24 12:19:06 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2013-09-24 12:19:06 +0000
commitb68e9d4dea7036d84321a93391c2f810766a41a0 (patch)
tree821235fdd65acf69ddee47af44a5dfd6889ce314 /Build/source/texk/dvipdf-x/xsrc/pdfobj.c
parent07ebfb83f578495e8f9e6826ca7a408470cf8b22 (diff)
dvipdf-x: Bug fix for xdvipdfm-res.test (tikz-bug)
git-svn-id: svn://tug.org/texlive/trunk@31738 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdf-x/xsrc/pdfobj.c')
-rw-r--r--Build/source/texk/dvipdf-x/xsrc/pdfobj.c394
1 files changed, 207 insertions, 187 deletions
diff --git a/Build/source/texk/dvipdf-x/xsrc/pdfobj.c b/Build/source/texk/dvipdf-x/xsrc/pdfobj.c
index 6c8d66780f4..78fb8aff21c 100644
--- a/Build/source/texk/dvipdf-x/xsrc/pdfobj.c
+++ b/Build/source/texk/dvipdf-x/xsrc/pdfobj.c
@@ -22,8 +22,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#if HAVE_CONFIG_H
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
#endif
#include <ctype.h>
@@ -117,6 +117,7 @@ struct pdf_stream
struct pdf_indirect
{
pdf_file *pf;
+ pdf_obj *obj; /* used when PF == NULL */
unsigned long label;
unsigned short generation;
};
@@ -161,6 +162,7 @@ struct pdf_file
FILE *file;
pdf_obj *trailer;
xref_entry *xref_table;
+ pdf_obj *catalog;
long num_obj;
long file_size;
int version;
@@ -179,6 +181,8 @@ static pdf_obj *xref_stream;
/* Internal static routines */
+static int check_for_pdf_version (FILE *file);
+
static void pdf_flush_obj (pdf_obj *object, FILE *file);
static void pdf_label_obj (pdf_obj *object);
static void pdf_write_obj (pdf_obj *object, FILE *file);
@@ -190,6 +194,7 @@ static void release_objstm (pdf_obj *objstm);
static void pdf_out_char (FILE *file, char c);
static void pdf_out (FILE *file, const void *buffer, long length);
+static pdf_obj *pdf_new_ref (pdf_obj *object);
static void release_indirect (pdf_indirect *data);
static void write_indirect (pdf_indirect *indirect, FILE *file);
@@ -314,13 +319,12 @@ pdf_out_init (const char *filename, int do_encryption)
if (filename == NULL) { /* no filename: writing to stdout */
#ifdef WIN32
- setmode(fileno(stdout), _O_BINARY);
+ setmode(fileno(stdout), _O_BINARY);
#endif
pdf_output_file = stdout;
}
else
pdf_output_file = MFOPEN(filename, FOPEN_WBIN_MODE);
-
if (!pdf_output_file) {
if (strlen(filename) < 128)
ERROR("Unable to open \"%s\".", filename);
@@ -510,14 +514,20 @@ pdf_set_info (pdf_obj *object)
}
void
-pdf_set_encrypt (pdf_obj *encrypt, pdf_obj *id)
+pdf_set_id (pdf_obj *id)
+{
+ if (pdf_add_dict(trailer_dict, pdf_new_name("ID"), id)) {
+ ERROR ("ID already set!");
+ }
+}
+
+void
+pdf_set_encrypt (pdf_obj *encrypt)
{
if (pdf_add_dict(trailer_dict, pdf_new_name("Encrypt"), pdf_ref_obj(encrypt))) {
ERROR("Encrypt object already set!");
}
encrypt->flags |= OBJ_NO_ENCRYPT;
-
- pdf_add_dict(trailer_dict, pdf_new_name("ID"), id);
}
static
@@ -588,16 +598,13 @@ void pdf_out_white (FILE *file)
ERROR("typecheck: Invalid object type: %d %d (line %d)", (o) ? (o)->type : -1, (t), __LINE__);\
}
-#define INVALIDOBJ(o) ((o) == NULL || (o)->type <= 0 || (o)->type > PDF_INDIRECT)
+#define INVALIDOBJ(o) ((o) == NULL || (o)->type <= 0 || (o)->type > PDF_UNDEFINED)
-pdf_obj *
+static pdf_obj *
pdf_new_obj(int type)
{
pdf_obj *result;
- if (type > PDF_INDIRECT || type < PDF_UNDEFINED)
- ERROR("Invalid object type: %d", type);
-
result = NEW(1, pdf_obj);
result->type = type;
result->data = NULL;
@@ -606,6 +613,9 @@ pdf_new_obj(int type)
result->refcount = 1;
result->flags = 0;
+ if (INVALIDOBJ(result))
+ ERROR("Invalid object type: %d", type);
+
return result;
}
@@ -634,6 +644,21 @@ pdf_label_obj (pdf_obj *object)
}
/*
+ * Transfer the label assigned to the object src to the object dst.
+ * The object dst must not yet have been labeled.
+ */
+void
+pdf_transfer_label (pdf_obj *dst, pdf_obj *src)
+{
+ ASSERT(dst && !dst->label && src);
+
+ dst->label = src->label;
+ dst->generation = src->generation;
+ src->label = 0;
+ src->generation = 0;
+}
+
+/*
* This doesn't really copy the object, but allows it to be used without
* fear that somebody else will free it.
*/
@@ -664,10 +689,7 @@ pdf_ref_obj (pdf_obj *object)
if (PDF_OBJ_INDIRECTTYPE(object)) {
return pdf_link_obj(object);
} else {
- if (object->label == 0) {
- pdf_label_obj(object);
- }
- return pdf_new_indirect(NULL, object->label, object->generation);
+ return pdf_new_ref(object);
}
}
@@ -688,6 +710,20 @@ write_indirect (pdf_indirect *indirect, FILE *file)
pdf_out(file, format_buffer, length);
}
+/* The undefined object is used as a placeholder in pdfnames.c
+ * for objects which are referenced before they are defined.
+ */
+pdf_obj *
+pdf_new_undefined (void)
+{
+ pdf_obj *result;
+
+ result = pdf_new_obj(PDF_UNDEFINED);
+ result->data = NULL;
+
+ return result;
+}
+
pdf_obj *
pdf_new_null (void)
{
@@ -741,6 +777,7 @@ write_boolean (pdf_boolean *data, FILE *file)
}
}
+#if 0
void
pdf_set_boolean (pdf_obj *object, char value)
{
@@ -751,6 +788,7 @@ pdf_set_boolean (pdf_obj *object, char value)
data = object->data;
data->value = value;
}
+#endif
char
pdf_boolean_value (pdf_obj *object)
@@ -824,19 +862,17 @@ pdf_new_string (const void *str, unsigned length)
pdf_obj *result;
pdf_string *data;
+ ASSERT(str);
+
result = pdf_new_obj(PDF_STRING);
data = NEW(1, pdf_string);
result->data = data;
- if (length != 0) {
- data->length = length;
- data->string = NEW(length+1, unsigned char);
- memcpy(data->string, str, length);
- /* Shouldn't assume NULL terminated. */
- data->string[length] = '\0';
- } else {
- data->length = 0;
- data->string = NULL;
- }
+
+ data->length = length;
+ data->string = NEW(length+1, unsigned char);
+ memcpy(data->string, str, length);
+ /* Shouldn't assume NULL terminated. */
+ data->string[length] = '\0';
return result;
}
@@ -1070,6 +1106,7 @@ release_name (pdf_name *data)
RELEASE(data);
}
+#if 0
void
pdf_set_name (pdf_obj *object, const char *name)
{
@@ -1091,6 +1128,7 @@ pdf_set_name (pdf_obj *object, const char *name)
data->name = NULL;
}
}
+#endif
char *
pdf_name_value (pdf_obj *object)
@@ -1268,7 +1306,7 @@ pdf_shift_array (pdf_obj *array)
return result;
}
-#endif /* 0 */
+#endif
/* Prepend an object to an array */
void
@@ -1309,19 +1347,26 @@ pdf_pop_array (pdf_obj *array)
return result;
}
-#endif /* 0 */
+#endif
+
static void
write_dict (pdf_dict *dict, FILE *file)
{
+#if 0
pdf_out (file, "<<\n", 3); /* dropping \n saves few kb. */
+#else
+ pdf_out (file, "<<", 2);
+#endif
while (dict->key != NULL) {
pdf_write_obj(dict->key, file);
if (pdf_need_white(PDF_NAME, (dict->value)->type)) {
pdf_out_white(file);
}
pdf_write_obj(dict->value, file);
+#if 0
pdf_out_char (file, '\n'); /* removing this saves few kb. */
+#endif
dict = dict->next;
}
pdf_out(file, ">>", 2);
@@ -1442,7 +1487,7 @@ pdf_put_dict (pdf_obj *dict, const char *key, pdf_obj *value)
data->value = value;
}
}
-#endif /* 0 */
+#endif
/* pdf_merge_dict makes a link for each item in dict2 before stealing it */
void
@@ -1902,7 +1947,7 @@ pdf_stream_get_flags (pdf_obj *stream)
return data->_flags;
}
-#endif /* 0 */
+#endif
static void
pdf_write_obj (pdf_obj *object, FILE *file)
@@ -1912,7 +1957,7 @@ pdf_write_obj (pdf_obj *object, FILE *file)
return;
}
- if (INVALIDOBJ(object))
+ if (INVALIDOBJ(object) || PDF_OBJ_UNDEFINED(object))
ERROR("pdf_write_obj: Invalid object, type = %d\n", object->type);
if (file == stderr)
@@ -2102,102 +2147,6 @@ pdf_release_obj (pdf_obj *object)
}
}
-/* Copy object data without changing object label. */
-void
-pdf_copy_object (pdf_obj *dst, pdf_obj *src)
-{
- if (!dst || !src)
- return;
-
- switch (dst->type) {
- case PDF_BOOLEAN: release_boolean(dst->data); break;
- case PDF_NULL: release_null(dst->data); break;
- case PDF_NUMBER: release_number(dst->data); break;
- case PDF_STRING: release_string(dst->data); break;
- case PDF_NAME: release_name(dst->data); break;
- case PDF_ARRAY: release_array(dst->data); break;
- case PDF_DICT: release_dict(dst->data); break;
- case PDF_STREAM: release_stream(dst->data); break;
- case PDF_INDIRECT: release_indirect(dst->data); break;
- }
-
- dst->type = src->type;
- switch (src->type) {
- case PDF_BOOLEAN:
- dst->data = NEW(1, pdf_boolean);
- pdf_set_boolean(dst, pdf_boolean_value(src));
- break;
- case PDF_NULL:
- dst->data = NULL;
- break;
- case PDF_NUMBER:
- dst->data = NEW(1, pdf_number);
- pdf_set_number(dst, pdf_number_value(src));
- break;
- case PDF_STRING:
- dst->data = NEW(1, pdf_string);
- pdf_set_string(dst,
- pdf_string_value(src),
- pdf_string_length(src));
- break;
- case PDF_NAME:
- dst->data = NEW(1, pdf_name);
- pdf_set_name(dst, pdf_name_value(src));
- break;
- case PDF_ARRAY:
- {
- pdf_array *data;
- unsigned long i;
-
- dst->data = data = NEW(1, pdf_array);
- data->size = 0;
- data->max = 0;
- data->values = NULL;
- for (i = 0; i < pdf_array_length(src); i++) {
- pdf_add_array(dst, pdf_link_obj(pdf_get_array(src, i)));
- }
- }
- break;
- case PDF_DICT:
- {
- pdf_dict *data;
-
- dst->data = data = NEW(1, pdf_dict);
- data->key = NULL;
- data->value = NULL;
- data->next = NULL;
- pdf_merge_dict(dst, src);
- }
- break;
- case PDF_STREAM:
- {
- pdf_stream *data;
-
- dst->data = data = NEW(1, pdf_stream);
- data->dict = pdf_new_dict();
- data->_flags = ((pdf_stream *)src->data)->_flags;
- data->stream_length = 0;
- data->max_length = 0;
-
- pdf_add_stream(dst, pdf_stream_dataptr(src), pdf_stream_length(src));
- pdf_merge_dict(data->dict, pdf_stream_dict(src));
- }
- break;
- case PDF_INDIRECT:
- {
- pdf_indirect *data;
-
- dst->data = data = NEW(1, pdf_indirect);
- data->pf = ((pdf_indirect *) (src->data))->pf;
- data->label = ((pdf_indirect *) (src->data))->label;
- data->generation = ((pdf_indirect *) (src->data))->generation;
- }
- break;
- }
-
- return;
-}
-
static int
backup_line (FILE *pdf_input_file)
{
@@ -2328,6 +2277,7 @@ pdf_new_indirect (pdf_file *pf, unsigned long obj_num, unsigned short obj_gen)
indirect = NEW(1, pdf_indirect);
indirect->pf = pf;
+ indirect->obj = NULL;
indirect->label = obj_num;
indirect->generation = obj_gen;
@@ -2562,27 +2512,53 @@ pdf_get_object (pdf_file *pf, unsigned long obj_num, unsigned short obj_gen)
}
#define OBJ_FILE(o) (((pdf_indirect *)((o)->data))->pf)
+#define OBJ_OBJ(o) (((pdf_indirect *)((o)->data))->obj)
#define OBJ_NUM(o) (((pdf_indirect *)((o)->data))->label)
#define OBJ_GEN(o) (((pdf_indirect *)((o)->data))->generation)
+static pdf_obj *
+pdf_new_ref (pdf_obj *object)
+{
+ pdf_obj *result;
+
+ if (object->label == 0) {
+ pdf_label_obj(object);
+ }
+ result = pdf_new_indirect(NULL, object->label, object->generation);
+ OBJ_OBJ(result) = object;
+ return result;
+}
+
/* pdf_deref_obj always returns a link instead of the original */
/* It never return the null object, but the NULL pointer instead */
pdf_obj *
pdf_deref_obj (pdf_obj *obj)
{
+ int count = PDF_OBJ_MAX_DEPTH;
+
if (obj)
obj = pdf_link_obj(obj);
- while (PDF_OBJ_INDIRECTTYPE(obj)) {
+ while (PDF_OBJ_INDIRECTTYPE(obj) && --count) {
pdf_file *pf = OBJ_FILE(obj);
- unsigned long obj_num = OBJ_NUM(obj);
- unsigned short obj_gen = OBJ_GEN(obj);
- if (!pf)
- ERROR("Tried to deref a non-file object");
- pdf_release_obj(obj);
- obj = pdf_get_object(pf, obj_num, obj_gen);
+ if (pf) {
+ unsigned long obj_num = OBJ_NUM(obj);
+ unsigned short obj_gen = OBJ_GEN(obj);
+ pdf_release_obj(obj);
+ obj = pdf_get_object(pf, obj_num, obj_gen);
+ } else {
+ pdf_obj *next_obj = OBJ_OBJ(obj);
+ if (!next_obj) {
+ ERROR("Undefined object reference");
+ }
+ pdf_release_obj(obj);
+ obj = pdf_link_obj(next_obj);
+ }
}
+ if (!count)
+ ERROR("Loop in object hierarchy detected. Broken PDF file?");
+
if (PDF_OBJ_NULLTYPE(obj)) {
pdf_release_obj(obj);
return NULL;
@@ -2740,7 +2716,7 @@ parse_xrefstm_subsec (pdf_file *pf,
static int
parse_xref_stream (pdf_file *pf, long xref_pos, pdf_obj **trailer)
{
- pdf_obj *xrefstm, *size_obj, *W_obj, *index;
+ pdf_obj *xrefstm, *size_obj, *W_obj, *index_obj;
unsigned long size;
long length;
int W[3], i, wsum = 0;
@@ -2780,17 +2756,17 @@ parse_xref_stream (pdf_file *pf, long xref_pos, pdf_obj **trailer)
p = pdf_stream_dataptr(xrefstm);
- index = pdf_lookup_dict(*trailer, "Index");
- if (index) {
+ index_obj = pdf_lookup_dict(*trailer, "Index");
+ if (index_obj) {
unsigned int index_len;
- if (!PDF_OBJ_ARRAYTYPE(index) ||
- ((index_len = pdf_array_length(index)) % 2 ))
+ if (!PDF_OBJ_ARRAYTYPE(index_obj) ||
+ ((index_len = pdf_array_length(index_obj)) % 2 ))
goto error;
i = 0;
while (i < index_len) {
- pdf_obj *first = pdf_get_array(index, i++);
- size_obj = pdf_get_array(index, i++);
+ pdf_obj *first = pdf_get_array(index_obj, i++);
+ size_obj = pdf_get_array(index_obj, i++);
if (!PDF_OBJ_NUMBERTYPE(first) ||
!PDF_OBJ_NUMBERTYPE(size_obj) ||
parse_xrefstm_subsec(pf, &p, &length, W, wsum,
@@ -2819,7 +2795,6 @@ parse_xref_stream (pdf_file *pf, long xref_pos, pdf_obj **trailer)
return 0;
}
-/* TODO: parse Version entry */
static pdf_obj *
read_xref (pdf_file *pf)
{
@@ -2904,6 +2879,7 @@ pdf_file_new (FILE *file)
pf->file = file;
pf->trailer = NULL;
pf->xref_table = NULL;
+ pf->catalog = NULL;
pf->num_obj = 0;
pf->version = 0;
@@ -2929,8 +2905,15 @@ pdf_file_free (pdf_file *pf)
pdf_release_obj(pf->xref_table[i].indirect);
}
- RELEASE(pf->xref_table);
- pdf_release_obj(pf->trailer);
+ RELEASE(pf->xref_table);
+ if (pf->trailer) {
+ pdf_release_obj(pf->trailer);
+ pf->trailer = NULL;
+ }
+ if (pf->catalog) {
+ pdf_release_obj(pf->catalog);
+ pf->catalog = NULL;
+ }
RELEASE(pf);
}
@@ -2942,45 +2925,90 @@ pdf_files_init (void)
ht_init_table(pdf_files, (void (*)(void *)) pdf_file_free);
}
+int
+pdf_file_get_version (pdf_file *pf)
+{
+ ASSERT(pf);
+ return pf->version;
+}
+
pdf_obj *
pdf_file_get_trailer (pdf_file *pf)
{
ASSERT(pf);
- return pdf_link_obj(pf->trailer);
+ return pf->trailer;
+}
+
+pdf_obj *
+pdf_file_get_catalog (pdf_file *pf)
+{
+ ASSERT(pf);
+ return pf->catalog;
}
pdf_file *
-pdf_open (char *ident, FILE *file)
+pdf_open (const char *ident, FILE *file)
{
- pdf_file *pf = NULL;
+ pdf_file *pf;
ASSERT(pdf_files);
- if (ident)
- pf = (pdf_file *) ht_lookup_table(pdf_files, ident, strlen(ident));
+ pf = (pdf_file *) ht_lookup_table(pdf_files, ident, strlen(ident));
if (pf) {
pf->file = file;
} else {
- int version = check_for_pdf(file);
- if (!version) {
- WARN("pdf_open: Not a PDF 1.[1-5] file.");
+ int version;
+ pdf_obj *new_version;
+
+ version = check_for_pdf_version(file);
+ if (version < 0) {
+ WARN("Not a PDF file.");
return NULL;
}
pf = pdf_file_new(file);
pf->version = version;
- if (!(pf->trailer = read_xref(pf))) {
- pdf_file_free(pf);
- return NULL;
+ if (!(pf->trailer = read_xref(pf)))
+ goto error;
+
+ if (pdf_lookup_dict(pf->trailer, "Encrypt")) {
+ WARN("PDF document is encrypted.");
+ goto error;
+ }
+
+ pf->catalog = pdf_deref_obj(pdf_lookup_dict(pf->trailer, "Root"));
+ if (!PDF_OBJ_DICTTYPE(pf->catalog)) {
+ WARN("Cannot read PDF document catalog. Broken PDF file?");
+ goto error;
}
- if (ident)
- ht_append_table(pdf_files, ident, strlen(ident), pf);
+ new_version = pdf_deref_obj(pdf_lookup_dict(pf->catalog, "Version"));
+ if (new_version) {
+ unsigned int minor;
+
+ if (!PDF_OBJ_NAMETYPE(new_version) ||
+ sscanf(pdf_name_value(new_version), "1.%u", &minor) != 1) {
+ pdf_release_obj(new_version);
+ WARN("Illegal Version entry in document catalog. Broken PDF file?");
+ goto error;
+ }
+
+ if (pf->version < minor)
+ pf->version = minor;
+
+ pdf_release_obj(new_version);
+ }
+
+ ht_append_table(pdf_files, ident, strlen(ident), pf);
}
return pf;
+
+ error:
+ pdf_file_free(pf);
+ return NULL;
}
void
@@ -2998,24 +3026,21 @@ pdf_files_close (void)
RELEASE(pdf_files);
}
-int
-check_for_pdf (FILE *file)
+static int
+check_for_pdf_version (FILE *file)
{
- int result = 0;
+ unsigned int minor;
rewind(file);
- if (fread(work_buffer, sizeof(char), strlen("%PDF-1.x"), file) ==
- strlen("%PDF-1.x") &&
- !strncmp(work_buffer, "%PDF-1.", strlen("%PDF-1."))) {
- if (work_buffer[7] >= '0' && work_buffer[7] <= '0' + pdf_version)
- result = 1;
- else {
- WARN("Version of PDF file (1.%c) is newer than version limit specification.",
- work_buffer[7]);
- }
- }
- return result;
+ return (ungetc(fgetc(file), file) == '%' &&
+ fscanf(file, "%%PDF-1.%u", &minor) == 1) ? minor : -1;
+}
+
+int
+check_for_pdf (FILE *file)
+{
+ return (check_for_pdf_version(file) >= 0);
}
static int CDECL
@@ -3035,6 +3060,8 @@ import_dict (pdf_obj *key, pdf_obj *value, void *pdata)
return 0;
}
+static pdf_obj loop_marker = { PDF_OBJ_INVALID, 0, 0, 0, 0, NULL };
+
static pdf_obj *
pdf_import_indirect (pdf_obj *object)
{
@@ -3052,15 +3079,16 @@ pdf_import_indirect (pdf_obj *object)
}
if ((ref = pf->xref_table[obj_num].indirect)) {
+ if (ref == &loop_marker)
+ ERROR("Loop in object hierarchy detected. Broken PDF file?");
return pdf_link_obj(ref);
} else {
pdf_obj *obj, *tmp;
obj = pdf_get_object(pf, obj_num, obj_gen);
- if (!obj) {
- WARN("Could not read object: %lu %u", obj_num, obj_gen);
- return NULL;
- }
+
+ /* We mark the reference to be able to detect loops */
+ pf->xref_table[obj_num].indirect = &loop_marker;
tmp = pdf_import_object(obj);
@@ -3146,25 +3174,17 @@ pdf_import_object (pdf_obj *object)
}
+/* returns 0 if indirect references point to the same object */
int
pdf_compare_reference (pdf_obj *ref1, pdf_obj *ref2)
{
pdf_indirect *data1, *data2;
- if (!PDF_OBJ_INDIRECTTYPE(ref1) ||
- !PDF_OBJ_INDIRECTTYPE(ref2)) {
- ERROR("Not indirect reference...");
- }
+ ASSERT(PDF_OBJ_INDIRECTTYPE(ref1) && PDF_OBJ_INDIRECTTYPE(ref2));
data1 = (pdf_indirect *) ref1->data;
data2 = (pdf_indirect *) ref2->data;
- if (data1->pf != data2->pf)
- return (int) (data1->pf - data2->pf);
- if (data1->label != data2->label)
- return (int) (data1->label - data2->label);
- if (data1->generation != data2->generation)
- return (int) (data1->generation - data2->generation);
-
- return 0;
+ return data1->pf != data2->pf || data1->label != data2->label
+ || data1->generation != data2->generation;
}