diff options
Diffstat (limited to 'Build/source/texk/dvipdfm-x/pdfobj.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/pdfobj.c | 1216 |
1 files changed, 722 insertions, 494 deletions
diff --git a/Build/source/texk/dvipdfm-x/pdfobj.c b/Build/source/texk/dvipdfm-x/pdfobj.c index 7cae7295356..9be1744ba2d 100644 --- a/Build/source/texk/dvipdfm-x/pdfobj.c +++ b/Build/source/texk/dvipdfm-x/pdfobj.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> @@ -35,6 +35,7 @@ #include "mfileio.h" #include "dpxconf.h" #include "dpxutil.h" + #include "pdflimits.h" #include "pdfencrypt.h" #include "pdfparse.h" @@ -60,13 +61,12 @@ /* Any of these types can be represented as follows */ struct pdf_obj { - int type; + int type; - unsigned int label; /* Only used for indirect objects - all other "label" to zero */ - unsigned short generation; /* Only used if "label" is used */ - unsigned refcount; /* Number of links to this object */ - int flags; + uint32_t label; /* Only used for indirect objects all other "label" to zero */ + uint16_t generation; /* Only used if "label" is used */ + int refcount; /* Number of links to this object */ + int32_t flags; void *data; #if defined(PDFOBJ_DEBUG) @@ -81,7 +81,7 @@ static int cur_obj_id = 0; struct pdf_boolean { - char value; + char value; }; struct pdf_number @@ -92,7 +92,7 @@ struct pdf_number struct pdf_string { unsigned char *string; - unsigned short length; + size_t length; }; struct pdf_name @@ -102,8 +102,8 @@ struct pdf_name struct pdf_array { - unsigned int max; - unsigned int size; + size_t max; + size_t size; struct pdf_obj **values; }; @@ -138,18 +138,18 @@ struct pdf_stream struct pdf_obj *dict; unsigned char *stream; int *objstm_data; /* used for object streams */ - unsigned int stream_length; - unsigned int max_length; + size_t stream_length; + size_t max_length; int32_t _flags; struct decode_parms decodeparms; }; struct pdf_indirect { - pdf_file *pf; - pdf_obj *obj; /* used when PF == NULL */ - unsigned label; - unsigned short generation; + pdf_file *pf; + pdf_obj *obj; /* used when PF == NULL */ + uint32_t label; + uint16_t generation; }; typedef void pdf_null; @@ -162,101 +162,182 @@ typedef struct pdf_dict pdf_dict; typedef struct pdf_stream pdf_stream; typedef struct pdf_indirect pdf_indirect; -static FILE *pdf_output_file = NULL; - -static int pdf_output_file_position = 0; -static int pdf_output_line_position = 0; -static int compression_saved = 0; - -#define FORMAT_BUF_SIZE 4096 -static char format_buffer[FORMAT_BUF_SIZE]; - typedef struct xref_entry { - unsigned char type; /* object storage type */ - unsigned int field2; /* offset in file or object stream */ - unsigned short field3; /* generation or index */ - pdf_obj *direct; /* used for imported objects */ - pdf_obj *indirect; /* used for imported objects */ + uint8_t type; /* object storage type */ + uint32_t field2; /* offset in file or object stream */ + uint16_t field3; /* generation or index */ + pdf_obj *direct; /* used for imported objects */ + pdf_obj *indirect; /* used for imported objects */ } xref_entry; -static xref_entry *output_xref; - -static unsigned int pdf_max_ind_objects; -static unsigned int next_label; - -static unsigned int startxref; - struct pdf_file { - FILE *file; - pdf_obj *trailer; - xref_entry *xref_table; - pdf_obj *catalog; - int num_obj; - int file_size; - int version; + FILE *file; + pdf_obj *trailer; + xref_entry *xref_table; + pdf_obj *catalog; + int num_obj; + int file_size; + int version; }; -static pdf_obj *output_stream; +static int error_out = 0; #define OBJSTM_MAX_OBJS 200 /* the limit is only 100 for linearized PDF */ -static int enc_mode; -static int doc_enc_mode; +struct pdf_out { + struct { + int enc_mode; /* boolean */ + } state; + + unsigned char id1[16]; + unsigned char id2[16]; + + struct { + int major; + int minor; + } version; + + struct { + struct { + int level; + int use_predictor; + } compression; + + int enable_encrypt; + int use_objstm; + } options; + + struct { + FILE *file; + size_t file_position; + int line_position; + size_t compression_saved; +#if defined(LIBDPX) + size_t file_stats; +#endif /* LIBDPX */ + } output; -static pdf_obj *trailer_dict; -static pdf_obj *xref_stream; + struct { + uint32_t next_label; + uint32_t max_ind_objects; + } obj; -/* Internal static routines */ + pdf_sec *sec_data; -static int check_for_pdf_version (FILE *file); + pdf_obj *trailer; + uint32_t startxref; + xref_entry * xref_table; -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); + pdf_obj *xref_stream; + pdf_obj *output_stream; + pdf_obj *current_objstm; +}; -static void set_objstm_data (pdf_obj *objstm, int *data); -static int *get_objstm_data (pdf_obj *objstm); -static void release_objstm (pdf_obj *objstm); +/* Underway to reform PDF related code... For a moment place pdf_out + * object as a static variable. */ +static pdf_out pout; -static void pdf_out_char (FILE *file, char c); -static void pdf_out (FILE *file, const void *buffer, int length); +static pdf_out * +current_output (void) +{ + return &pout; +} -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); +static void +init_pdf_out_struct (pdf_out *p) +{ + ASSERT(p); -static void release_boolean (pdf_obj *data); -static void write_boolean (pdf_boolean *data, FILE *file); + p->state.enc_mode = 0; -static void write_null (FILE *file); + memset(p->id1, 0, 16); + memset(p->id2, 0, 16); -static void release_number (pdf_number *number); -static void write_number (pdf_number *number, FILE *file); + p->version.major = 1; + p->version.minor = PDF_VERSION_DEFAULT; -static void write_string (pdf_string *str, FILE *file); -static void release_string (pdf_string *str); + p->options.compression.level = 9; + p->options.compression.use_predictor = 1; + p->options.enable_encrypt = 0; + p->options.use_objstm = 1; -static void write_name (pdf_name *name, FILE *file); -static void release_name (pdf_name *name); + p->output.file = NULL; + p->output.file_position = 0; + p->output.line_position = 0; + p->output.compression_saved = 0; +#if defined(LIBDPX) + p->output.file_stats = 0; +#endif /* LIBDPX */ -static void write_array (pdf_array *array, FILE *file); -static void release_array (pdf_array *array); + p->obj.next_label = 1; + p->obj.max_ind_objects = 0; -static void write_dict (pdf_dict *dict, FILE *file); -static void release_dict (pdf_dict *dict); + p->sec_data = NULL; + p->trailer = NULL; + p->startxref = 0; + p->xref_table = NULL; -static void write_stream (pdf_stream *stream, FILE *file); -static void release_stream (pdf_stream *stream); + p->xref_stream = NULL; + p->output_stream = NULL; + p->current_objstm = NULL; +} -static char compression_level = 9; -static char compression_use_predictor = 1; +static void +clean_pdf_out_struct (pdf_out *p) +{ + memset(p, 0, sizeof(pdf_out)); +} -void -pdf_set_compression (int level) +/* Internal static routines */ + +static int check_for_pdf_version (FILE *file); + +static void pdf_flush_obj (pdf_out *p, pdf_obj *object); +static void pdf_label_obj (pdf_out *p, pdf_obj *object); +static void pdf_write_obj (pdf_out *p, pdf_obj *object); + +static void set_objstm_data (pdf_obj *objstm, int *data); +static int *get_objstm_data (pdf_obj *objstm); +static void release_objstm (pdf_obj *objstm); + +static void pdf_out_char (pdf_out *p, char c); +static void pdf_out_str (pdf_out *p, const void *buffer, size_t length); + +static pdf_obj *pdf_new_ref (pdf_out *p, pdf_obj *object); +static void release_indirect (pdf_indirect *data); +static void write_indirect (pdf_out *p, pdf_indirect *indirect); + +static void release_boolean (pdf_obj *data); +static void write_boolean (pdf_out *p, pdf_boolean *data); + +static void write_null (pdf_out *p); + +static void release_number (pdf_number *number); +static void write_number (pdf_out *p, pdf_number *number); + +static void write_string (pdf_out *p, pdf_string *str); +static void release_string (pdf_string *str); + +static void write_name (pdf_out *p, pdf_name *name); +static void release_name (pdf_name *name); + +static void write_array (pdf_out *p, pdf_array *array); +static void release_array (pdf_array *array); + +static void write_dict (pdf_out *p, pdf_dict *dict); +static void release_dict (pdf_dict *dict); + +static void write_stream (pdf_out *p, pdf_stream *stream); +static void release_stream (pdf_stream *stream); + +static void +pdf_out_set_compression (pdf_out *p, int level) { + ASSERT(p); + #ifndef HAVE_ZLIB ERROR("You don't have compression compiled in. Possibly libz wasn't found by configure."); #else @@ -265,7 +346,7 @@ pdf_set_compression (int level) WARN("Unable to set compression level -- your zlib doesn't have compress2()."); #endif if (level >= 0 && level <= 9) - compression_level = level; + p->options.compression.level = level; else { ERROR("set_compression: invalid compression level: %d", level); } @@ -277,156 +358,233 @@ pdf_set_compression (int level) FILE * pdf_get_output_file (void) { - return pdf_output_file; + pdf_out *p = current_output(); + return p->output.file; } -static int pdf_version = PDF_VERSION_DEFAULT; - -void -pdf_set_version (int version) +static void +pdf_out_set_version (pdf_out *p, int ver_major, int ver_minor) { + int version; + + ASSERT(p); + + version = ver_major * 10 + ver_minor; /* Don't forget to update CIDFont_stdcc_def[] in cid.c too! */ if (version >= PDF_VERSION_MIN && version <= PDF_VERSION_MAX) { - pdf_version = version; + p->version.major = ver_major; + p->version.minor = ver_minor; + } else { + WARN("Unsupported PDF version %d.%d ... Ignoring.", ver_major, ver_minor); } } int pdf_get_version (void) { - return pdf_version; + pdf_out *p = current_output(); + return (p->version.major * 10 + p->version.minor); } int pdf_get_version_major (void) { - return pdf_version/10; + pdf_out *p = current_output(); + return p->version.major; } int pdf_get_version_minor (void) { - return pdf_version%10; + pdf_out *p = current_output(); + return p->version.minor; } int pdf_check_version (int major, int minor) { - return (pdf_version >= major*10+minor) ? 0 : -1; -} + pdf_out *p = current_output(); + if (p->version.major > major) + return 0; + else if (p->version.major < major) + return -1; + else { + return (p->version.minor >= minor) ? 0 : -1; + } -static pdf_obj *current_objstm = NULL; -static int do_objstm; + return -1; +} static void -add_xref_entry (unsigned label, unsigned char type, unsigned int field2, unsigned short field3) +add_xref_entry (pdf_out *p, + uint32_t label, uint8_t type, uint32_t field2, uint16_t field3) { - if (label >= pdf_max_ind_objects) { - pdf_max_ind_objects = (label/IND_OBJECTS_ALLOC_SIZE+1)*IND_OBJECTS_ALLOC_SIZE; - output_xref = RENEW(output_xref, pdf_max_ind_objects, xref_entry); + ASSERT(p); + + if (label >= p->obj.max_ind_objects) { + p->obj.max_ind_objects = (label/IND_OBJECTS_ALLOC_SIZE+1)*IND_OBJECTS_ALLOC_SIZE; + p->xref_table = RENEW(p->xref_table, p->obj.max_ind_objects, xref_entry); } - output_xref[label].type = type; - output_xref[label].field2 = field2; - output_xref[label].field3 = field3; - output_xref[label].direct = NULL; - output_xref[label].indirect = NULL; + p->xref_table[label].type = type; + p->xref_table[label].field2 = field2; + p->xref_table[label].field3 = field3; + p->xref_table[label].direct = NULL; + p->xref_table[label].indirect = NULL; } #define BINARY_MARKER "%\344\360\355\370\n" -void +pdf_out * pdf_out_init (const char *filename, - int do_encryption, int enable_objstm, int enable_predictor) + const unsigned char *id1, + const unsigned char *id2, + int ver_major, int ver_minor, int compression_level, + int enable_encrypt, + int enable_objstm, + int enable_predictor) { - char v; + pdf_out *p = current_output(); + char v; + + init_pdf_out_struct(p); + + pdf_out_set_version(p, ver_major, ver_minor); + pdf_out_set_compression(p, compression_level); - output_xref = NULL; - pdf_max_ind_objects = 0; - add_xref_entry(0, 0, 0, 0xffff); - next_label = 1; + add_xref_entry(p, 0, 0, 0, 0xffff); - if (pdf_version >= 15) { + /* This must be set before pdf_set_root() is called */ + p->options.enable_encrypt = enable_encrypt; + if (pdf_check_version(1, 5) == 0) { if (enable_objstm) { - xref_stream = pdf_new_stream(STREAM_COMPRESS); - xref_stream->flags |= OBJ_NO_ENCRYPT; - trailer_dict = pdf_stream_dict(xref_stream); - pdf_add_dict(trailer_dict, pdf_new_name("Type"), pdf_new_name("XRef")); - do_objstm = 1; + p->xref_stream = pdf_new_stream(STREAM_COMPRESS); + p->xref_stream->flags |= OBJ_NO_ENCRYPT; + p->trailer = pdf_stream_dict(p->xref_stream); + pdf_add_dict(p->trailer, pdf_new_name("Type"), pdf_new_name("XRef")); + p->options.use_objstm = 1; } else { - trailer_dict = pdf_new_dict(); - do_objstm = 0; + p->xref_stream = NULL; + p->trailer = pdf_new_dict(); + p->options.use_objstm = 0; } } else { - xref_stream = NULL; - trailer_dict = pdf_new_dict(); - do_objstm = 0; + p->xref_stream = NULL; + p->trailer = pdf_new_dict(); + p->options.use_objstm = 0; } - output_stream = NULL; + p->output_stream = NULL; if (filename == NULL) { /* no filename: writing to stdout */ #ifdef WIN32 setmode(fileno(stdout), _O_BINARY); #endif - pdf_output_file = stdout; + p->output.file = stdout; } else { - pdf_output_file = MFOPEN(filename, FOPEN_WBIN_MODE); - if (!pdf_output_file) { + p->output.file = MFOPEN(filename, FOPEN_WBIN_MODE); + if (!p->output.file) { if (strlen(filename) < 128) ERROR("Unable to open \"%s\".", filename); else ERROR("Unable to open file."); } } - pdf_out(pdf_output_file, "%PDF-", strlen("%PDF-")); - v = '0' + (pdf_version / 10); - pdf_out(pdf_output_file, &v, 1); - pdf_out(pdf_output_file, ".", 1); - v = '0' + (pdf_version % 10); - pdf_out(pdf_output_file, &v, 1); - pdf_out(pdf_output_file, "\n", 1); - pdf_out(pdf_output_file, BINARY_MARKER, strlen(BINARY_MARKER)); + pdf_out_str(p, "%PDF-", strlen("%PDF-")); + v = '0' + p->version.major; + pdf_out_str(p, &v, 1); + pdf_out_str(p, ".", 1); + v = '0' + p->version.minor; + pdf_out_str(p, &v, 1); + pdf_out_str(p, "\n", 1); + pdf_out_str(p, BINARY_MARKER, strlen(BINARY_MARKER)); + + /* Set trailer ID and setup security handler */ + { + pdf_obj *id_array; + + memcpy(p->id1, id1, 16); + memcpy(p->id2, id2, 16); + id_array = pdf_new_array(); + pdf_add_array(id_array, pdf_new_string(p->id1, 16)); + pdf_add_array(id_array, pdf_new_string(p->id2, 16)); + pdf_add_dict(p->trailer, pdf_new_name("ID"), id_array); + } + p->state.enc_mode = 0; + p->options.compression.use_predictor = enable_predictor; - enc_mode = 0; - doc_enc_mode = do_encryption; - compression_use_predictor = enable_predictor; + return p; +} + +void +pdf_out_set_encrypt (int keybits, int32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata) +{ + pdf_out *p = current_output(); + + pdf_obj *encrypt, *extension, *catalog; + + p->sec_data = pdf_enc_init(p->id1, keybits, permission, + opasswd, upasswd, use_aes, encrypt_metadata); + if (!p->sec_data) { + p->options.enable_encrypt = 0; + return; + } + + encrypt = pdf_enc_get_encrypt_dict(p->sec_data); + pdf_add_dict(p->trailer, + pdf_new_name("Encrypt"), pdf_ref_obj(encrypt)); + encrypt->flags |= OBJ_NO_ENCRYPT; + encrypt->flags |= OBJ_NO_OBJSTM; + pdf_release_obj(encrypt); + + extension = pdf_enc_get_extension_dict(p->sec_data); + if (extension) { + catalog = pdf_doc_catalog(); + pdf_add_dict(catalog, pdf_new_name("Extensions"), extension); + } } static void -dump_xref_table (void) +dump_xref_table (pdf_out *p) { - int length; - unsigned int i; + int i, length; + char buf[32]; - pdf_out(pdf_output_file, "xref\n", 5); + ASSERT(p); - length = sprintf(format_buffer, "%d %u\n", 0, next_label); - pdf_out(pdf_output_file, format_buffer, length); + pdf_out_str(p, "xref\n", 5); + + length = sprintf(buf, "%d %u\n", 0, p->obj.next_label); + pdf_out_str(p, buf, length); /* * Every space counts. The space after the 'f' and 'n' is * *essential*. * The PDF spec says the lines must be 20 characters long including the * end of line character. */ - for (i = 0; i < next_label; i++) { - unsigned char type = output_xref[i].type; + for (i = 0; i < p->obj.next_label; i++) { + uint8_t type = p->xref_table[i].type; if (type > 1) ERROR("object type %hu not allowed in xref table", type); - length = sprintf(format_buffer, "%010u %05hu %c \n", - output_xref[i].field2, output_xref[i].field3, - type ? 'n' : 'f'); - pdf_out(pdf_output_file, format_buffer, length); + length = sprintf(buf, "%010u %05hu %c \n", + p->xref_table[i].field2, p->xref_table[i].field3, + type ? 'n' : 'f'); + pdf_out_str(p, buf, length); } } static void -dump_trailer_dict (void) +dump_trailer (pdf_out *p) { - pdf_out(pdf_output_file, "trailer\n", 8); - enc_mode = 0; - write_dict(trailer_dict->data, pdf_output_file); - pdf_release_obj(trailer_dict); - pdf_out_char(pdf_output_file, '\n'); + ASSERT(p); + + pdf_out_str(p, "trailer\n", 8); + p->state.enc_mode = 0; + write_dict(p, p->trailer->data); + pdf_release_obj(p->trailer); + p->trailer = NULL; + pdf_out_char(p, '\n'); } /* @@ -434,16 +592,17 @@ dump_trailer_dict (void) * contributed by Matthias Franz (March 21, 2007) */ static void -dump_xref_stream (void) +dump_xref_stream (pdf_out *p) { - unsigned int pos, i; - unsigned poslen; + uint32_t pos, i; + uint32_t poslen; unsigned char buf[7] = {0, 0, 0, 0, 0}; + pdf_obj *w; - pdf_obj *w; + ASSERT(p); /* determine the necessary size of the offset field */ - pos = startxref; /* maximal offset value */ + pos = p->startxref; /* maximal offset value */ poslen = 1; while (pos >>= 8) poslen++; @@ -452,48 +611,52 @@ dump_xref_stream (void) pdf_add_array(w, pdf_new_number(1)); /* type */ pdf_add_array(w, pdf_new_number(poslen)); /* offset (big-endian) */ pdf_add_array(w, pdf_new_number(2)); /* generation */ - pdf_add_dict(trailer_dict, pdf_new_name("W"), w); + pdf_add_dict(p->trailer, pdf_new_name("W"), w); /* We need the xref entry for the xref stream right now */ - add_xref_entry(next_label-1, 1, startxref, 0); + add_xref_entry(p, p->obj.next_label - 1, 1, p->startxref, 0); - for (i = 0; i < next_label; i++) { - unsigned j; - unsigned short f3; - buf[0] = output_xref[i].type; - pos = output_xref[i].field2; + for (i = 0; i < p->obj.next_label; i++) { + size_t j; + uint16_t f3; + buf[0] = p->xref_table[i].type; + pos = p->xref_table[i].field2; for (j = poslen; j--; ) { buf[1+j] = (unsigned char) pos; pos >>= 8; } - f3 = output_xref[i].field3; + f3 = p->xref_table[i].field3; buf[poslen+1] = (unsigned char) (f3 >> 8); buf[poslen+2] = (unsigned char) (f3); - pdf_add_stream(xref_stream, &buf, poslen+3); + pdf_add_stream(p->xref_stream, &buf, poslen+3); } - pdf_release_obj(xref_stream); + pdf_release_obj(p->xref_stream); + p->xref_stream = NULL; } #if defined(LIBDPX) -static long pdf_output_file_stats = 0; long pdf_output_stats (void) { - return pdf_output_file_stats; + pdf_out *p = current_output(); + return p->output.file_stats; } #endif /* LIBDPX */ void pdf_out_flush (void) { - if (pdf_output_file) { - int length; + pdf_out *p = current_output(); + char buf[16]; + + if (p->output.file) { + int length; /* Flush current object stream */ - if (current_objstm) { - release_objstm(current_objstm); - current_objstm =NULL; + if (p->current_objstm) { + release_objstm(p->current_objstm); + p->current_objstm =NULL; } /* @@ -501,53 +664,56 @@ pdf_out_flush (void) * for the xref stream dictionary (= trailer). * Labelling it in pdf_out_init (with 1) does not work (why?). */ - if (xref_stream) - pdf_label_obj(xref_stream); + if (p->xref_stream) + pdf_label_obj(p, p->xref_stream); /* Record where this xref is for trailer */ - startxref = pdf_output_file_position; + p->startxref = p->output.file_position; - pdf_add_dict(trailer_dict, pdf_new_name("Size"), - pdf_new_number(next_label)); + pdf_add_dict(p->trailer, + pdf_new_name("Size"), pdf_new_number(p->obj.next_label)); - if (xref_stream) - dump_xref_stream(); + if (p->xref_stream) + dump_xref_stream(p); else { - dump_xref_table(); - dump_trailer_dict(); + dump_xref_table(p); + dump_trailer(p); } /* Done with xref table */ - RELEASE(output_xref); + RELEASE(p->xref_table); + p->xref_table = NULL; - pdf_out(pdf_output_file, "startxref\n", 10); - length = sprintf(format_buffer, "%u\n", startxref); - pdf_out(pdf_output_file, format_buffer, length); - pdf_out(pdf_output_file, "%%EOF\n", 6); + pdf_out_str(p, "startxref\n", 10); + length = sprintf(buf, "%u\n", p->startxref); + pdf_out_str(p, buf, length); + pdf_out_str(p, "%%EOF\n", 6); #if !defined(LIBDPX) MESG("\n"); #endif /* !LIBDPX */ if (dpx_conf.verbose_level > 0) { - if (compression_level > 0) { - MESG("Compression saved %ld bytes%s\n", compression_saved, - pdf_version < 15 ? ". Try \"-V 1.5\" for better compression" : ""); + if (p->options.compression.level > 0) { + MESG("Compression saved %ld bytes%s\n", p->output.compression_saved); } } #if !defined(LIBDPX) - MESG("%ld bytes written", pdf_output_file_position); + MESG("%ld bytes written", p->output.file_position); #else - pdf_output_file_stats = pdf_output_file_position; + p->output.file_stats = p->output.file_position; #endif /* !LIBDPX */ - MFCLOSE(pdf_output_file); - pdf_output_file_position = 0; - pdf_output_line_position = 0; - pdf_output_file = NULL; + MFCLOSE(p->output.file); + p->output.file = NULL; + p->output.file_position = 0; + p->output.line_position = 0; } + if (p->sec_data) + pdf_enc_close(&p->sec_data); #if defined(PDFOBJ_DEBUG) { int i; + error_out = 1; MESG("\ndebug>> %d PDF objects created.", cur_obj_id); for (i = 0; i < cur_obj_id; i++) { pdf_obj *obj = bucket[i]; @@ -555,110 +721,113 @@ pdf_out_flush (void) if (obj->label > 0) { WARN("Object obj_id=<%lu, %u> unreleased...", obj->label, obj->generation); WARN("Reference count=%d", obj->refcount); + pdf_write_obj(p, obj); + MESG("\n"); } else { - WARN("Unreleased object found: %d", i); - pdf_write_obj(obj, stderr); + WARN("Unreleased object found: (unlabeled) id=%d", i); + pdf_write_obj(p, obj); MESG("\n"); } } } } #endif + clean_pdf_out_struct(p); } void pdf_error_cleanup (void) { + pdf_out *p = current_output(); /* * This routine is the cleanup required for an abnormal exit. * For now, simply close the file. */ - if (pdf_output_file) - MFCLOSE(pdf_output_file); - pdf_output_file = NULL; + if (p->output.file) + MFCLOSE(p->output.file); + p->output.file = NULL; } void pdf_set_root (pdf_obj *object) { - if (pdf_add_dict(trailer_dict, pdf_new_name("Root"), pdf_ref_obj(object))) { + pdf_out *p = current_output(); + + if (pdf_lookup_dict(p->trailer, "Root")) ERROR("Root object already set!"); - } + pdf_add_dict(p->trailer, pdf_new_name("Root"), pdf_ref_obj(object)); /* Adobe Readers don't like a document catalog inside an encrypted * object stream, although the PDF v1.5 spec seems to allow this. * Note that we don't set OBJ_NO_ENCRYPT since the name dictionary in * a document catalog may contain strings, which should be encrypted. */ - if (doc_enc_mode) + if (p->options.enable_encrypt) object->flags |= OBJ_NO_OBJSTM; } void pdf_set_info (pdf_obj *object) { - if (pdf_add_dict(trailer_dict, pdf_new_name("Info"), pdf_ref_obj(object))) { + pdf_out *p = current_output(); + + if (pdf_lookup_dict(p->trailer, "Info")) ERROR ("Info object already set!"); - } + pdf_add_dict(p->trailer, pdf_new_name("Info"), pdf_ref_obj(object)); } -void -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; -} -static -void pdf_out_char (FILE *file, char c) +static void +pdf_out_char (pdf_out *p, char c) { - if (output_stream && file == pdf_output_file) - pdf_add_stream(output_stream, &c, 1); - else { - fputc(c, file); - /* Keep tallys for xref table *only* if writing a pdf file. */ - if (file == pdf_output_file) { - pdf_output_file_position += 1; + ASSERT(p); + + if (error_out) { + fputc(c, stderr); + } else { + if (p->output_stream) + pdf_add_stream(p->output_stream, &c, 1); + else { + fputc(c, p->output.file); + p->output.file_position += 1; if (c == '\n') - pdf_output_line_position = 0; + p->output.line_position = 0; else - pdf_output_line_position += 1; + p->output.line_position += 1; } } } static char xchar[] = "0123456789abcdef"; -#define pdf_out_xchar(f,c) do {\ - pdf_out_char((f), xchar[((c) >> 4) & 0x0f]);\ - pdf_out_char((f), xchar[(c) & 0x0f]);\ -} while (0) +static void +pdf_out_xchar (pdf_out *p, char c) +{ + ASSERT(p); -static -void pdf_out (FILE *file, const void *buffer, int length) + pdf_out_char(p, xchar[(c >> 4) & 0x0f]); + pdf_out_char(p, xchar[c & 0x0f]); +} + +static void +pdf_out_str (pdf_out *p, const void *buffer, size_t length) { - if (output_stream && file == pdf_output_file) - pdf_add_stream(output_stream, buffer, length); + ASSERT(p); + + if (error_out) + fwrite(buffer, 1, length, stderr); else { - fwrite(buffer, 1, length, file); - /* Keep tallys for xref table *only* if writing a pdf file */ - if (file == pdf_output_file) { - pdf_output_file_position += length; - pdf_output_line_position += length; + if (p->output_stream) + pdf_add_stream(p->output_stream, buffer, length); + else { + fwrite(buffer, 1, length, p->output.file); + p->output.file_position += length; + p->output.line_position += length; /* "foo\nbar\n "... */ if (length > 0 && - ((const char *)buffer)[length-1] == '\n') - pdf_output_line_position = 0; + ((const char *)buffer)[length-1] == '\n') + p->output.line_position = 0; } } } @@ -674,12 +843,14 @@ int pdf_need_white (int type1, int type2) } static -void pdf_out_white (FILE *file) +void pdf_out_white (pdf_out *p) { - if (file == pdf_output_file && pdf_output_line_position >= 80) { - pdf_out_char(file, '\n'); + ASSERT(p); + + if (p->output.line_position >= 80) { + pdf_out_char(p, '\n'); } else { - pdf_out_char(file, ' '); + pdf_out_char(p, ' '); } } @@ -724,8 +895,10 @@ pdf_obj_typeof (pdf_obj *object) } static void -pdf_label_obj (pdf_obj *object) +pdf_label_obj (pdf_out *p, pdf_obj *object) { + ASSERT(p); + if (INVALIDOBJ(object)) ERROR("pdf_label_obj(): passed invalid object."); @@ -733,7 +906,7 @@ pdf_label_obj (pdf_obj *object) * Don't change label on an already labeled object. Ignore such calls. */ if (object->label == 0) { - object->label = next_label++; + object->label = p->obj.next_label++; object->generation = 0; } } @@ -772,19 +945,23 @@ pdf_link_obj (pdf_obj *object) pdf_obj * pdf_ref_obj (pdf_obj *object) { + pdf_out *p = current_output(); + if (INVALIDOBJ(object)) ERROR("pdf_ref_obj(): passed invalid object."); if (object->refcount == 0) { MESG("\nTrying to refer already released object!!!\n"); - pdf_write_obj(object, stderr); + error_out = 1; + pdf_write_obj(p, object); ERROR("Cannot continue..."); + error_out = 0; } if (PDF_OBJ_INDIRECTTYPE(object)) { return pdf_link_obj(object); } else { - return pdf_new_ref(object); + return pdf_new_ref(p, object); } } @@ -795,14 +972,17 @@ release_indirect (pdf_indirect *data) } static void -write_indirect (pdf_indirect *indirect, FILE *file) +write_indirect (pdf_out *p, pdf_indirect *indirect) { - int length; + int length; + char buf[64]; + ASSERT(p); ASSERT(!indirect->pf); - length = sprintf(format_buffer, "%u %hu R", indirect->label, indirect->generation); - pdf_out(file, format_buffer, length); + length = sprintf(buf, "%u %hu R", + indirect->label, indirect->generation); + pdf_out_str(p, buf, length); } /* The undefined object is used as a placeholder in pdfnames.c @@ -831,9 +1011,9 @@ pdf_new_null (void) } static void -write_null (FILE *file) +write_null (pdf_out *p) { - pdf_out(file, "null", 4); + pdf_out_str(p, "null", 4); } pdf_obj * @@ -857,12 +1037,12 @@ release_boolean (pdf_obj *data) } static void -write_boolean (pdf_boolean *data, FILE *file) +write_boolean (pdf_out *p, pdf_boolean *data) { if (data->value) { - pdf_out(file, "true", 4); + pdf_out_str(p, "true", 4); } else { - pdf_out(file, "false", 5); + pdf_out_str(p, "false", 5); } } @@ -899,13 +1079,14 @@ release_number (pdf_number *data) } static void -write_number (pdf_number *number, FILE *file) +write_number (pdf_out *p, pdf_number *number) { - int count; + int count; + char buf[512]; - count = pdf_sprint_number(format_buffer, number->value); + count = pdf_sprint_number(buf, number->value); - pdf_out(file, format_buffer, count); + pdf_out_str(p, buf, count); } @@ -938,20 +1119,20 @@ 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; data->length = length; - if (str && length > 0) { + if (length) { data->string = NEW(length+1, unsigned char); memcpy(data->string, str, length); /* Shouldn't assume NULL terminated. */ data->string[length] = '\0'; - } else { + } else data->string = NULL; - data->length = 0; - } return result; } @@ -977,7 +1158,7 @@ pdf_string_length (pdf_obj *object) data = object->data; - return (unsigned) (data->length); + return (unsigned) data->length; } /* @@ -987,8 +1168,8 @@ pdf_string_length (pdf_obj *object) int pdfobj_escape_str (char *buffer, int bufsize, const unsigned char *s, int len) { - int result = 0; - int i; + size_t result = 0; + size_t i; for (i = 0; i < len; i++) { unsigned char ch; @@ -1031,21 +1212,22 @@ pdfobj_escape_str (char *buffer, int bufsize, const unsigned char *s, int len) } } - return result; + return (int) result; } static void -write_string (pdf_string *str, FILE *file) +write_string (pdf_out *p, pdf_string *str) { - unsigned char *s = NULL; - char wbuf[FORMAT_BUF_SIZE]; /* Shouldn't use format_buffer[]. */ - int nescc = 0, i, count; - size_t len = 0; + unsigned char *s = NULL; + size_t i, nescc = 0; + size_t len = 0; - if (enc_mode) { - pdf_encrypt_data(str->string, str->length, &s, &len); + ASSERT(p); + + if (p->state.enc_mode) { + pdf_encrypt_data(p->sec_data, str->string, str->length, &s, &len); } else { - s = str->string; + s = str->string; len = str->length; } @@ -1061,13 +1243,22 @@ write_string (pdf_string *str, FILE *file) * ASCII hex string. */ if (nescc > len / 3) { - pdf_out_char(file, '<'); + pdf_out_char(p, '<'); for (i = 0; i < len; i++) { - pdf_out_xchar(file, s[i]); + pdf_out_xchar(p, s[i]); } - pdf_out_char(file, '>'); + pdf_out_char(p, '>'); } else { - pdf_out_char(file, '('); + char *buf; + size_t size, count; + + /* At most len/3 is to be escaped here. (see above) + * Thus 4*len/3 + 2*len/3 + 2 is enough for buffer size. + */ + size = len * 2 + 3; + buf = NEW(size, char); + + pdf_out_char(p, '('); /* * This section of code probably isn't speed critical. Escaping the * characters in the string one at a time may seem slow, but it's @@ -1077,12 +1268,14 @@ write_string (pdf_string *str, FILE *file) * handled as quickly as possible since there are so many of them. */ for (i = 0; i < len; i++) { - count = pdfobj_escape_str(wbuf, FORMAT_BUF_SIZE, &(s[i]), 1); - pdf_out(file, wbuf, count); + count = pdfobj_escape_str(buf, size, &(s[i]), 1); + pdf_out_str(p, buf, count); } - pdf_out_char(file, ')'); + pdf_out_char(p, ')'); + RELEASE(buf); } - if (enc_mode && s) + + if (p->state.enc_mode && s) RELEASE(s); } @@ -1123,7 +1316,7 @@ pdf_obj * pdf_new_name (const char *name) { pdf_obj *result; - unsigned length; + size_t length; pdf_name *data; result = pdf_new_obj(PDF_NAME); @@ -1142,10 +1335,12 @@ pdf_new_name (const char *name) } static void -write_name (pdf_name *name, FILE *file) +write_name (pdf_out *p, pdf_name *name) { - char *s; - int i, length; + char *s; + size_t i, length; + + ASSERT(p); s = name->name; length = name->name ? strlen(name->name) : 0; @@ -1169,14 +1364,14 @@ write_name (pdf_name *name, FILE *file) (c) == '{' || (c) == '}' || \ (c) == '%') #endif - pdf_out_char(file, '/'); + pdf_out_char(p, '/'); for (i = 0; i < length; i++) { if (s[i] < '!' || s[i] > '~' || s[i] == '#' || is_delim(s[i])) { /* ^ "space" is here. */ - pdf_out_char (file, '#'); - pdf_out_xchar(file, s[i]); + pdf_out_char (p, '#'); + pdf_out_xchar(p, s[i]); } else { - pdf_out_char (file, s[i]); + pdf_out_char (p, s[i]); } } } @@ -1225,25 +1420,27 @@ pdf_new_array (void) } static void -write_array (pdf_array *array, FILE *file) +write_array (pdf_out *p, pdf_array *array) { - pdf_out_char(file, '['); + ASSERT(p); + + pdf_out_char(p, '['); if (array->size > 0) { - unsigned int i; - int type1 = PDF_UNDEFINED, type2; + size_t i; + int type1 = PDF_UNDEFINED, type2; for (i = 0; i < array->size; i++) { if (array->values[i]) { - type2 = array->values[i]->type; - if (type1 != PDF_UNDEFINED && pdf_need_white(type1, type2)) - pdf_out_white(file); - type1 = type2; - pdf_write_obj(array->values[i], file); + type2 = array->values[i]->type; + if (type1 != PDF_UNDEFINED && pdf_need_white(type1, type2)) + pdf_out_white(p); + type1 = type2; + pdf_write_obj(p, array->values[i]); } else - WARN("PDF array element #ld undefined.", i); + WARN("PDF array element #ld undefined.", i); } } - pdf_out_char(file, ']'); + pdf_out_char(p, ']'); } pdf_obj * @@ -1264,7 +1461,7 @@ pdf_get_array (pdf_obj *array, int idx) return result; } -unsigned int +unsigned pdf_array_length (pdf_obj *array) { pdf_array *data; @@ -1273,13 +1470,13 @@ pdf_array_length (pdf_obj *array) data = (pdf_array *) array->data; - return (unsigned int) data->size; + return (unsigned) data->size; } static void release_array (pdf_array *data) { - unsigned int i; + size_t i; if (data->values) { for (i = 0; i < data->size; i++) { @@ -1316,7 +1513,7 @@ pdf_add_array (pdf_obj *array, pdf_obj *object) #if 0 void -pdf_put_array (pdf_obj *array, unsigned idx, pdf_obj *object) +pdf_put_array (pdf_obj *array, int idx, pdf_obj *object) { pdf_array *data; int i; @@ -1357,7 +1554,7 @@ pdf_shift_array (pdf_obj *array) data = array->data; if (data->size > 0) { - int i; + size_t i; result = data->values[0]; for (i = 1; i < data->size; i++) @@ -1409,25 +1606,25 @@ pdf_pop_array (pdf_obj *array) #endif static void -write_dict (pdf_dict *dict, FILE *file) +write_dict (pdf_out *p, pdf_dict *dict) { #if 0 - pdf_out (file, "<<\n", 3); /* dropping \n saves few kb. */ + pdf_out_str (p, "<<\n", 3); /* dropping \n saves few kb. */ #else - pdf_out (file, "<<", 2); + pdf_out_str(p, "<<", 2); #endif while (dict->key != NULL) { - pdf_write_obj(dict->key, file); + pdf_write_obj(p, dict->key); if (pdf_need_white(PDF_NAME, (dict->value)->type)) { - pdf_out_white(file); + pdf_out_white(p); } - pdf_write_obj(dict->value, file); + pdf_write_obj(p, dict->value); #if 0 pdf_out_char (file, '\n'); /* removing this saves few kb. */ #endif dict = dict->next; } - pdf_out (file, ">>", 2); + pdf_out_str(p, ">>", 2); } pdf_obj * @@ -1826,7 +2023,9 @@ filter_PNG15_apply_filter (unsigned char *raster, return dst; } -/* This modifies "raster" itself! */ +/* TIFF predictor filter support + * This modifies "raster" itself! + */ static void apply_filter_TIFF2_1_2_4 (unsigned char *raster, int32_t width, int32_t height, @@ -1880,7 +2079,8 @@ apply_filter_TIFF2_1_2_4 (unsigned char *raster, } } if (outbits > 0) { - raster[k] = (outbuf << (8 - outbits)); k++; + raster[k] = (outbuf << (8 - outbits)); + k++; } } RELEASE(prev); @@ -1966,17 +2166,19 @@ filter_create_predictor_dict (int predictor, int32_t columns, } static void -write_stream (pdf_stream *stream, FILE *file) +write_stream (pdf_out *p, pdf_stream *stream) { unsigned char *filtered; - unsigned int filtered_length; + size_t filtered_length; #ifdef HAVE_ZLIB uLong buffer_length; #else - unsigned int buffer_length; + size_t buffer_length; #endif unsigned char *buffer; + ASSERT(p); + /* * Always work from a copy of the stream. All filters read from * "filtered" and leave their result in "filtered". @@ -2001,11 +2203,11 @@ write_stream (pdf_stream *stream, FILE *file) /* Apply compression filter if requested */ if (stream->stream_length > 0 && (stream->_flags & STREAM_COMPRESS) && - compression_level > 0) { + p->options.compression.level > 0) { pdf_obj *filters; /* First apply predictor filter if requested. */ - if ( compression_use_predictor && + if ( p->options.compression.use_predictor && (stream->_flags & STREAM_USE_PREDICTOR) && !pdf_lookup_dict(stream->dict, "DecodeParms")) { int bits_per_pixel = stream->decodeparms.colors * @@ -2071,18 +2273,19 @@ write_stream (pdf_stream *stream, FILE *file) } #ifdef HAVE_ZLIB_COMPRESS2 if (compress2(buffer, &buffer_length, filtered, - filtered_length, compression_level)) { + filtered_length, p->options.compression.level)) { ERROR("Zlib error"); } #else if (compress(buffer, &buffer_length, filtered, - filtered_length)) { + filtered_length)) { ERROR ("Zlib error"); } #endif /* HAVE_ZLIB_COMPRESS2 */ RELEASE(filtered); - compression_saved += filtered_length - buffer_length - - (filters ? strlen("/FlateDecode "): strlen("/Filter/FlateDecode\n")); + p->output.compression_saved += + filtered_length - buffer_length + - (filters ? strlen("/FlateDecode "): strlen("/Filter/FlateDecode\n")); filtered = buffer; filtered_length = buffer_length; @@ -2090,10 +2293,10 @@ write_stream (pdf_stream *stream, FILE *file) #endif /* HAVE_ZLIB */ /* AES will change the size of data! */ - if (enc_mode) { + if (p->state.enc_mode) { unsigned char *cipher = NULL; size_t cipher_len = 0; - pdf_encrypt_data(filtered, filtered_length, &cipher, &cipher_len); + pdf_encrypt_data(p->sec_data, filtered, filtered_length, &cipher, &cipher_len); RELEASE(filtered); filtered = cipher; filtered_length = cipher_len; @@ -2115,12 +2318,12 @@ write_stream (pdf_stream *stream, FILE *file) pdf_add_dict(stream->dict, pdf_new_name("Length"), pdf_new_number(filtered_length)); - pdf_write_obj(stream->dict, file); + pdf_write_obj(p, stream->dict); - pdf_out(file, "\nstream\n", 8); + pdf_out_str(p, "\nstream\n", 8); if (filtered_length > 0) - pdf_out(file, filtered, filtered_length); + pdf_out_str(p, filtered, filtered_length); RELEASE(filtered); /* @@ -2130,8 +2333,8 @@ write_stream (pdf_stream *stream, FILE *file) * filters, this could be a problem. */ - pdf_out(file, "\n", 1); - pdf_out(file, "endstream", 9); + pdf_out_str(p, "\n", 1); + pdf_out_str(p, "endstream", 9); } static void @@ -2497,7 +2700,7 @@ filter_stream_decode_FlateDecode (const void *data, size_t len, struct decode_pa WARN("Ignoring zlib error: status=%d, message=\"%s\"", status, z.msg); break; } else if (status != Z_OK) { - WARN("inflate() failed (status=%d, message=\"%s\").", status, z.msg); + WARN("inflate() failed. Broken PDF file?"); inflateEnd(&z); pdf_release_obj(tmp); return NULL; @@ -2861,76 +3064,83 @@ pdf_stream_get_flags (pdf_obj *stream) #endif static void -pdf_write_obj (pdf_obj *object, FILE *file) +pdf_write_obj (pdf_out *p, pdf_obj *object) { + ASSERT(p); + if (object == NULL) { - write_null(file); + write_null(p); return; } if (INVALIDOBJ(object) || PDF_OBJ_UNDEFINED(object)) ERROR("pdf_write_obj: Invalid object, type = %d\n", object->type); - if (file == stderr) + if (error_out) fprintf(stderr, "{%d}", object->refcount); switch (object->type) { case PDF_BOOLEAN: - write_boolean(object->data, file); + write_boolean(p, object->data); break; case PDF_NUMBER: - write_number (object->data, file); + write_number (p, object->data); break; case PDF_STRING: - write_string (object->data, file); + write_string (p, object->data); break; case PDF_NAME: - write_name(object->data, file); + write_name(p, object->data); break; case PDF_ARRAY: - write_array(object->data, file); + write_array(p, object->data); break; case PDF_DICT: - write_dict (object->data, file); + write_dict (p, object->data); break; case PDF_STREAM: - write_stream(object->data, file); + write_stream(p, object->data); break; case PDF_NULL: - write_null(file); + write_null(p); break; case PDF_INDIRECT: - write_indirect(object->data, file); + write_indirect(p, object->data); break; } } /* Write the object to the file */ static void -pdf_flush_obj (pdf_obj *object, FILE *file) +pdf_flush_obj (pdf_out *p, pdf_obj *object) { - int length; + size_t length; + char buf[64]; /* * Record file position */ - add_xref_entry(object->label, 1, - pdf_output_file_position, object->generation); - length = sprintf(format_buffer, "%u %hu obj\n", object->label, object->generation); - enc_mode = doc_enc_mode && !(object->flags & OBJ_NO_ENCRYPT); - pdf_enc_set_label(object->label); - pdf_enc_set_generation(object->generation); - pdf_out(file, format_buffer, length); - pdf_write_obj(object, file); - pdf_out(file, "\nendobj\n", 8); + add_xref_entry(p, object->label, 1, + p->output.file_position, object->generation); + length = sprintf(buf, "%u %hu obj\n", object->label, object->generation); + p->state.enc_mode = + (p->options.enable_encrypt && !(object->flags & OBJ_NO_ENCRYPT)) ? 1 : 0; + if (p->state.enc_mode) { + pdf_enc_set_label(p->sec_data, object->label); + pdf_enc_set_generation(p->sec_data, object->generation); + } + pdf_out_str(p, buf, length); + pdf_write_obj(p, object); + pdf_out_str(p, "\nendobj\n", 8); } static int -pdf_add_objstm (pdf_obj *objstm, pdf_obj *object) +pdf_add_objstm (pdf_out *p, pdf_obj *objstm, pdf_obj *object) { int *data, pos; TYPECHECK(objstm, PDF_STREAM); + ASSERT(p); data = get_objstm_data(objstm); pos = ++data[0]; @@ -2938,14 +3148,14 @@ pdf_add_objstm (pdf_obj *objstm, pdf_obj *object) data[2*pos] = object->label; data[2*pos+1] = pdf_stream_length(objstm); - add_xref_entry(object->label, 2, objstm->label, pos-1); + add_xref_entry(p, object->label, 2, objstm->label, pos-1); /* redirect output into objstm */ - output_stream = objstm; - enc_mode = 0; - pdf_write_obj(object, pdf_output_file); - pdf_out_char(pdf_output_file, '\n'); - output_stream = NULL; + p->output_stream = objstm; + p->state.enc_mode = 0; + pdf_write_obj(p, object); + pdf_out_char(p, '\n'); + p->output_stream = NULL; return pos; } @@ -2958,7 +3168,7 @@ release_objstm (pdf_obj *objstm) pdf_obj *dict; pdf_stream *stream; unsigned char *old_buf; - unsigned int old_length; + size_t old_length; stream = (pdf_stream *) objstm->data; /* Precede stream data by offset table */ @@ -2971,8 +3181,9 @@ release_objstm (pdf_obj *objstm) { int i = 2*pos, *val = data+2; while (i--) { - int length = sprintf(format_buffer, "%d ", *(val++)); - pdf_add_stream(objstm, format_buffer, length); + char buf[32]; + size_t length = sprintf(buf, "%d ", *(val++)); + pdf_add_stream(objstm, buf, length); } } @@ -2989,13 +3200,17 @@ release_objstm (pdf_obj *objstm) void pdf_release_obj (pdf_obj *object) { + pdf_out *p = current_output(); + if (object == NULL) return; if (INVALIDOBJ(object) || object->refcount <= 0) { MESG("\npdf_release_obj: object=%p, type=%d, refcount=%d\n", - object, object->type, object->refcount); - pdf_write_obj(object, stderr); + object, object->type, object->refcount); + error_out = 1; + pdf_write_obj(p, object); ERROR("pdf_release_obj: Called with invalid object."); + error_out = 0; } object->refcount -= 1; if (object->refcount == 0) { @@ -3006,23 +3221,23 @@ pdf_release_obj (pdf_obj *object) * Nothing is using this object so it's okay to remove it. * Nonzero "label" means object needs to be written before it's destroyed. */ - if (object->label && pdf_output_file != NULL) { - if (!do_objstm || object->flags & OBJ_NO_OBJSTM - || (doc_enc_mode && object->flags & OBJ_NO_ENCRYPT) - || object->generation) - pdf_flush_obj(object, pdf_output_file); + if (object->label && p->output.file != NULL) { + if (!p->options.use_objstm || object->flags & OBJ_NO_OBJSTM || + (p->options.enable_encrypt && (object->flags & OBJ_NO_ENCRYPT)) || + object->generation) + pdf_flush_obj(p, object); else { - if (!current_objstm) { - int *data = NEW(2*OBJSTM_MAX_OBJS+2, int); - data[0] = data[1] = 0; - current_objstm = pdf_new_stream(STREAM_COMPRESS); - set_objstm_data(current_objstm, data); - pdf_label_obj(current_objstm); - } - if (pdf_add_objstm(current_objstm, object) == OBJSTM_MAX_OBJS) { - release_objstm(current_objstm); - current_objstm = NULL; - } + if (!p->current_objstm) { + int *data = NEW(2*OBJSTM_MAX_OBJS+2, int); + data[0] = data[1] = 0; + p->current_objstm = pdf_new_stream(STREAM_COMPRESS); + set_objstm_data(p->current_objstm, data); + pdf_label_obj(p, p->current_objstm); + } + if (pdf_add_objstm(p, p->current_objstm, object) == OBJSTM_MAX_OBJS) { + release_objstm(p->current_objstm); + p->current_objstm = NULL; + } } } switch (object->type) { @@ -3060,6 +3275,9 @@ pdf_release_obj (pdf_obj *object) } } +/* Reading external PDF files + * + */ static int backup_line (FILE *pdf_input_file) { @@ -3086,11 +3304,11 @@ backup_line (FILE *pdf_input_file) static int find_xref (FILE *pdf_input_file) { - int xref_pos = 0; - int len, tries = 10; + size_t len, xref_pos = 0; + int tries = 10; do { - int currentpos; + size_t currentpos; if (!backup_line(pdf_input_file)) { tries = 0; @@ -3162,10 +3380,11 @@ parse_trailer (pdf_file *pf) * :-( */ static int -next_object_offset (pdf_file *pf, unsigned int obj_num) +next_object_offset (pdf_file *pf, uint32_t obj_num) { - int next = pf->file_size; /* Worst case */ - int i, curr; + uint32_t next = pf->file_size; /* Worst case */ + size_t i; + uint32_t curr; curr = pf->xref_table[obj_num].field2; /* Check all other type 1 objects to find next one */ @@ -3184,7 +3403,7 @@ next_object_offset (pdf_file *pf, unsigned int obj_num) ((pf)->xref_table[(n)].type == 2 && !(g)))) pdf_obj * -pdf_new_indirect (pdf_file *pf, unsigned obj_num, unsigned short obj_gen) +pdf_new_indirect (pdf_file *pf, uint32_t obj_num, uint16_t obj_gen) { pdf_obj *result; pdf_indirect *indirect; @@ -3202,13 +3421,12 @@ pdf_new_indirect (pdf_file *pf, unsigned obj_num, unsigned short obj_gen) } static pdf_obj * -pdf_read_object (unsigned int obj_num, unsigned short obj_gen, - pdf_file *pf, int offset, int limit) +pdf_read_object (uint32_t obj_num, uint16_t obj_gen, pdf_file *pf, size_t offset, size_t limit) { - int length; - char *buffer; + pdf_obj *result = NULL; + size_t length; + char *buffer; const char *p, *endptr; - pdf_obj *result; length = limit - offset; @@ -3227,7 +3445,7 @@ pdf_read_object (unsigned int obj_num, unsigned short obj_gen, { const char *q = p; /* <== p */ char *sp; - unsigned int n, g; + uint32_t n, g; skip_white(&q, endptr); sp = parse_unsigned(&q, endptr); @@ -3279,16 +3497,16 @@ pdf_read_object (unsigned int obj_num, unsigned short obj_gen, } static pdf_obj * -read_objstm (pdf_file *pf, unsigned int num) +read_objstm (pdf_file *pf, uint32_t num) { - unsigned int offset = pf->xref_table[num].field2; - unsigned short gen = pf->xref_table[num].field3; - int limit = next_object_offset(pf, num), n, first, *header = NULL; - char *data = NULL, *q; + size_t offset = pf->xref_table[num].field2; + uint16_t gen = pf->xref_table[num].field3; + size_t limit = next_object_offset(pf, num); + int n, first, *header = NULL; + char *data = NULL, *q; const char *p, *endptr; - int i; - - pdf_obj *objstm, *dict, *type, *n_obj, *first_obj; + int i; + pdf_obj *objstm, *dict, *type, *n_obj, *first_obj; objstm = pdf_read_object(num, gen, pf, offset, limit); @@ -3365,7 +3583,7 @@ read_objstm (pdf_file *pf, unsigned int num) * several cross-reference sections. */ static pdf_obj * -pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) +pdf_get_object (pdf_file *pf, uint32_t obj_num, uint16_t obj_gen) { pdf_obj *result; @@ -3381,27 +3599,27 @@ pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) if (pf->xref_table[obj_num].type == 1) { /* type == 1 */ - unsigned int offset; - int limit; + uint32_t offset; + size_t limit; offset = pf->xref_table[obj_num].field2; limit = next_object_offset(pf, obj_num); result = pdf_read_object(obj_num, obj_gen, pf, offset, limit); } else { /* type == 2 */ - unsigned int objstm_num = pf->xref_table[obj_num].field2; - unsigned short index = pf->xref_table[obj_num].field3; - pdf_obj *objstm; - int *data, n, first, length; + uint32_t objstm_num = pf->xref_table[obj_num].field2; + uint16_t index = pf->xref_table[obj_num].field3; + pdf_obj *objstm; + int *data, n, first, length; const char *p, *q; if (objstm_num >= pf->num_obj || - pf->xref_table[objstm_num].type != 1 || - !((objstm = pf->xref_table[objstm_num].direct) || - (objstm = read_objstm(pf, objstm_num)))) + pf->xref_table[objstm_num].type != 1 || + !((objstm = pf->xref_table[objstm_num].direct) || + (objstm = read_objstm(pf, objstm_num)))) goto error; - data = get_objstm_data(objstm); - n = *(data++); + data = get_objstm_data(objstm); + n = *(data++); first = *(data++); if (index >= n || data[2*index] != obj_num) @@ -3431,12 +3649,14 @@ pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) #define OBJ_GEN(o) (((pdf_indirect *)((o)->data))->generation) static pdf_obj * -pdf_new_ref (pdf_obj *object) +pdf_new_ref (pdf_out *p, pdf_obj *object) { pdf_obj *result; + ASSERT(p); + if (object->label == 0) { - pdf_label_obj(object); + pdf_label_obj(p, object); } result = pdf_new_indirect(NULL, object->label, object->generation); OBJ_OBJ(result) = object; @@ -3456,8 +3676,8 @@ pdf_deref_obj (pdf_obj *obj) while (PDF_OBJ_INDIRECTTYPE(obj) && --count) { pdf_file *pf = OBJ_FILE(obj); if (pf) { - unsigned int obj_num = OBJ_NUM(obj); - unsigned short obj_gen = OBJ_GEN(obj); + uint32_t obj_num = OBJ_NUM(obj); + uint16_t obj_gen = OBJ_GEN(obj); pdf_release_obj(obj); obj = pdf_get_object(pf, obj_num, obj_gen); } else { @@ -3481,9 +3701,9 @@ pdf_deref_obj (pdf_obj *obj) } static void -extend_xref (pdf_file *pf, int new_size) +extend_xref (pdf_file *pf, size_t new_size) { - unsigned int i; + size_t i; pf->xref_table = RENEW(pf->xref_table, new_size, xref_entry); for (i = pf->num_obj; i < new_size; i++) { @@ -3498,12 +3718,12 @@ extend_xref (pdf_file *pf, int new_size) /* Returns < 0 for error, 1 for success, and 0 when xref stream found. */ static int -parse_xref_table (pdf_file *pf, int xref_pos) +parse_xref_table (pdf_file *pf, size_t xref_pos) { FILE *pdf_input_file = pf->file; const char *p, *endptr; char buf[256]; /* See, PDF ref. v.1.7, p.91 for "255+1" here. */ - int len; + size_t len; /* * This routine reads one xref segment. It may be called multiple times @@ -3535,10 +3755,10 @@ parse_xref_table (pdf_file *pf, int xref_pos) /* Next line in file has first item and size of table */ for (;;) { - char flag; - unsigned int current_pos; - int i; - uint32_t first, size, offset, obj_gen; + char flag; + size_t current_pos, size, offset; + int i; + uint32_t first, obj_gen; current_pos = tell_position(pdf_input_file); len = mfreadln(buf, 255, pdf_input_file); @@ -3702,10 +3922,10 @@ parse_xref_table (pdf_file *pf, int xref_pos) return 1; } -static unsigned int -parse_xrefstm_field (const char **p, int length, unsigned int def) +static uint32_t +parse_xrefstm_field (const char **p, size_t length, uint32_t def) { - unsigned int val = 0; + uint32_t val = 0; if (!length) return def; @@ -3720,9 +3940,9 @@ parse_xrefstm_field (const char **p, int length, unsigned int def) static int parse_xrefstm_subsec (pdf_file *pf, - const char **p, int *length, - int *W, int wsum, - int first, int size) { + const char **p, size_t *length, + int *W, int wsum, int first, int size) +{ xref_entry *e; if ((*length -= wsum*size) < 0) @@ -3733,9 +3953,9 @@ parse_xrefstm_subsec (pdf_file *pf, e = pf->xref_table + first; while (size--) { - unsigned char type; - unsigned int field2; - unsigned short field3; + uint8_t type; + uint32_t field2; + uint16_t field3; type = (unsigned char) parse_xrefstm_field(p, W[0], 1); if (type > 2) @@ -3746,8 +3966,8 @@ parse_xrefstm_subsec (pdf_file *pf, return -1; #endif - field2 = (unsigned int) parse_xrefstm_field(p, W[1], 0); - field3 = (unsigned short) parse_xrefstm_field(p, W[2], 0); + field2 = (uint32_t) parse_xrefstm_field(p, W[1], 0); + field3 = (uint16_t) parse_xrefstm_field(p, W[2], 0); if (!e->field2) { e->type = type; @@ -3761,12 +3981,12 @@ parse_xrefstm_subsec (pdf_file *pf, } static int -parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) +parse_xref_stream (pdf_file *pf, size_t xref_pos, pdf_obj **trailer) { - pdf_obj *xrefstm, *size_obj, *W_obj, *index_obj; - unsigned int size; - int length; - int W[3], i, wsum = 0; + pdf_obj *xrefstm, *size_obj, *W_obj, *index_obj; + uint32_t size; + size_t length; + int W[3], i, wsum = 0; const char *p; xrefstm = pdf_read_object(0, 0, pf, xref_pos, pf->file_size); @@ -3786,7 +4006,7 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) size_obj = pdf_lookup_dict(*trailer, "Size"); if (!PDF_OBJ_NUMBERTYPE(size_obj)) goto error; - size = (unsigned int) pdf_number_value(size_obj); + size = (uint32_t) pdf_number_value(size_obj); length = pdf_stream_length(xrefstm); @@ -3805,7 +4025,7 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) index_obj = pdf_lookup_dict(*trailer, "Index"); if (index_obj) { - unsigned int index_len; + size_t index_len; if (!PDF_OBJ_ARRAYTYPE(index_obj) || ((index_len = pdf_array_length(index_obj)) % 2 )) goto error; @@ -3845,7 +4065,7 @@ static pdf_obj * read_xref (pdf_file *pf) { pdf_obj *trailer = NULL, *main_trailer = NULL; - int xref_pos; + size_t xref_pos; if (!(xref_pos = find_xref(pf->file))) goto error; @@ -3859,37 +4079,37 @@ read_xref (pdf_file *pf) pdf_obj *xrefstm; if (!(trailer = parse_trailer(pf))) - goto error; + goto error; if (!main_trailer) - main_trailer = pdf_link_obj(trailer); + main_trailer = pdf_link_obj(trailer); if ((xrefstm = pdf_lookup_dict(trailer, "XRefStm"))) { - pdf_obj *new_trailer = NULL; - if (PDF_OBJ_NUMBERTYPE(xrefstm) && - parse_xref_stream(pf, (int) pdf_number_value(xrefstm), + pdf_obj *new_trailer = NULL; + if (PDF_OBJ_NUMBERTYPE(xrefstm) && + parse_xref_stream(pf, (int) pdf_number_value(xrefstm), &new_trailer)) - pdf_release_obj(new_trailer); - else - WARN("Skipping hybrid reference section."); - /* Many PDF 1.5 xref streams use DecodeParms, which we cannot - parse. This way we can use at least xref tables in hybrid - documents. Or should we better stop parsing the file? - */ + pdf_release_obj(new_trailer); + else + WARN("Skipping hybrid reference section."); + /* Many PDF 1.5 xref streams use DecodeParms, which we cannot + * parse. This way we can use at least xref tables in hybrid + * documents. Or should we better stop parsing the file? + */ } } else if (!res && parse_xref_stream(pf, xref_pos, &trailer)) { /* cross-reference stream */ if (!main_trailer) - main_trailer = pdf_link_obj(trailer); + main_trailer = pdf_link_obj(trailer); } else goto error; if ((prev = pdf_lookup_dict(trailer, "Prev"))) { if (PDF_OBJ_NUMBERTYPE(prev)) - xref_pos = (int) pdf_number_value(prev); + xref_pos = (size_t) pdf_number_value(prev); else - goto error; + goto error; } else xref_pos = 0; @@ -3938,7 +4158,7 @@ pdf_file_new (FILE *file) static void pdf_file_free (pdf_file *pf) { - unsigned int i; + size_t i; if (!pf) { return; @@ -3995,6 +4215,7 @@ pdf_file_get_catalog (pdf_file *pf) pdf_file * pdf_open (const char *ident, FILE *file) { + pdf_out *p = current_output(); pdf_file *pf = NULL; ASSERT(pdf_files); @@ -4008,15 +4229,21 @@ pdf_open (const char *ident, FILE *file) pdf_obj *new_version; int version = check_for_pdf_version(file); - if (version < 10) - WARN("Unrecognized PDF version specified for input PDF file: %d.%d", - pdf_version/10, pdf_version%10); - else if (version > pdf_version) { - WARN("Trying to include PDF file with version (%d.%d), which is " \ - "newer than current output PDF setting (%d.%d).", - version/10, version%10, pdf_version/10, pdf_version%10); - } + if (!dpx_conf.is_xbb) { + int ver_major, ver_minor; + ver_major = version / 10; + ver_minor = version % 10; + + if (version < 10) + WARN("Unrecognized PDF version specified for input PDF file: %d.%d", + ver_major, ver_minor); + else if (pdf_check_version(ver_major, ver_minor) < 0) { + WARN("Trying to include PDF file with version (%d.%d), which is " \ + "newer than current output PDF setting (%d.%d).", + ver_major, ver_minor, p->version.major, p->version.minor); + } + } pf = pdf_file_new(file); pf->version = version; @@ -4096,7 +4323,7 @@ check_for_pdf (FILE *file) if (version < 0) /* not a PDF file */ return 0; - if (version <= pdf_version) + if (version <= pdf_get_version()) return 1; return 1; @@ -4122,10 +4349,11 @@ import_dict (pdf_obj *key, pdf_obj *value, void *pdata) static pdf_obj * pdf_import_indirect (pdf_obj *object) { + pdf_out *p = current_output(); pdf_file *pf = OBJ_FILE(object); - unsigned int obj_num = OBJ_NUM(object); - unsigned short obj_gen = OBJ_GEN(object); - pdf_obj *ref; + uint32_t obj_num = OBJ_NUM(object); + uint16_t obj_gen = OBJ_GEN(object); + pdf_obj *ref; ASSERT(pf); @@ -4154,7 +4382,7 @@ pdf_import_indirect (pdf_obj *object) * are completely read. */ reserved = pdf_new_null(); /* for reservation of label */ - pf->xref_table[obj_num].indirect = ref = pdf_new_ref(reserved); + pf->xref_table[obj_num].indirect = ref = pdf_new_ref(p, reserved); imported = pdf_import_object(obj); if (imported) { if (imported->label) { @@ -4187,7 +4415,7 @@ pdf_import_object (pdf_obj *object) { pdf_obj *imported; pdf_obj *tmp; - int i; + size_t i; switch (pdf_obj_typeof(object)) { @@ -4233,8 +4461,8 @@ pdf_import_object (pdf_obj *object) for (i = 0; i < pdf_array_length(object); i++) { tmp = pdf_import_object(pdf_get_array(object, i)); if (!tmp) { - pdf_release_obj(imported); - return NULL; + pdf_release_obj(imported); + return NULL; } pdf_add_array(imported, tmp); } |