summaryrefslogtreecommitdiff
path: root/src/pdflib/pdflib/p_document.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdflib/pdflib/p_document.c')
-rw-r--r--src/pdflib/pdflib/p_document.c1939
1 files changed, 1939 insertions, 0 deletions
diff --git a/src/pdflib/pdflib/p_document.c b/src/pdflib/pdflib/p_document.c
new file mode 100644
index 0000000..4c00aa3
--- /dev/null
+++ b/src/pdflib/pdflib/p_document.c
@@ -0,0 +1,1939 @@
+/*---------------------------------------------------------------------------*
+ | PDFlib - A library for generating PDF on the fly |
+ +---------------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+ +---------------------------------------------------------------------------+
+ | |
+ | This software is subject to the PDFlib license. It is NOT in the |
+ | public domain. Extended versions and commercial licenses are |
+ | available, please check http://www.pdflib.com. |
+ | |
+ *---------------------------------------------------------------------------*/
+
+/* $Id: p_document.c,v 1.1 2008/10/17 06:11:49 scuri Exp $
+ *
+ * PDFlib document related routines
+ *
+ */
+
+
+#undef MVS_TEST
+
+#define P_DOCUMENT_C
+
+/* For checking the beta expiration date */
+#include <time.h>
+
+#include "p_intern.h"
+#include "p_image.h"
+#include "p_layer.h"
+#include "p_page.h"
+#include "p_tagged.h"
+
+
+
+
+
+#if (defined(WIN32) || defined(OS2)) && !defined(WINCE)
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+
+/* file attachment structure */
+typedef struct
+{
+ char *filename;
+ char *name;
+ char *description;
+ char *mimetype;
+ pdc_off_t filesize;
+}
+pdf_attachments;
+
+#define PDF_MAX_LANGCODE 8
+
+/* Document open modes */
+
+typedef enum
+{
+ open_auto,
+ open_none,
+ open_bookmarks,
+ open_thumbnails,
+ open_fullscreen,
+ open_attachments
+
+}
+pdf_openmode;
+
+static const pdc_keyconn pdf_openmode_keylist[] =
+{
+ {"none", open_none},
+ {"bookmarks", open_bookmarks},
+ {"thumbnails", open_thumbnails},
+ {"fullscreen", open_fullscreen},
+ {"attachments", open_attachments},
+
+ {NULL, 0}
+};
+
+static const pdc_keyconn pdf_openmode_pdfkeylist[] =
+{
+ {"UseNone", open_auto},
+ {"UseNone", open_none},
+ {"UseOutlines", open_bookmarks},
+ {"UseThumbs", open_thumbnails},
+ {"FullScreen", open_fullscreen},
+ {"UseAttachments", open_attachments},
+
+ {NULL, 0}
+};
+
+
+/* Document page layout */
+
+typedef enum
+{
+ layout_default,
+ layout_singlepage,
+ layout_onecolumn,
+ layout_twocolumnleft,
+ layout_twocolumnright,
+ layout_twopageleft,
+ layout_twopageright
+}
+pdf_pagelayout;
+
+static const pdc_keyconn pdf_pagelayout_pdfkeylist[] =
+{
+ {"Default", layout_default},
+ {"SinglePage", layout_singlepage},
+ {"OneColumn", layout_onecolumn},
+ {"TwoColumnLeft", layout_twocolumnleft},
+ {"TwoColumnRight", layout_twocolumnright},
+ {"TwoPageLeft", layout_twopageleft},
+ {"TwoPageRight", layout_twopageright},
+ {NULL, 0}
+};
+
+
+/* NonFullScreenPageMode */
+
+static const pdc_keyconn pdf_nonfullscreen_keylist[] =
+{
+ {"none", open_none},
+ {"bookmarks", open_bookmarks},
+ {"thumbnails", open_thumbnails},
+
+ {NULL, 0}
+};
+
+typedef enum
+{
+ doc_none,
+ doc_l2r,
+ doc_r2l,
+ doc_appdefault,
+ doc_simplex,
+ doc_duplexflipshortedge,
+ doc_duplexfliplongedge
+}
+pdf_viewerprefence;
+
+/* Direction */
+
+static const pdc_keyconn pdf_textdirection_pdfkeylist[] =
+{
+ {"L2R", doc_l2r},
+ {"R2L", doc_r2l},
+ {NULL, 0}
+};
+
+/* PrintScaling */
+
+static const pdc_keyconn pdf_printscaling_pdfkeylist[] =
+{
+ {"None", doc_none},
+ {"AppDefault", doc_appdefault},
+ {NULL, 0}
+};
+
+/* Duplex */
+
+static const pdc_keyconn pdf_duplex_pdfkeylist[] =
+{
+ {"None", doc_none},
+ {"Simplex", doc_simplex},
+ {"DuplexFlipShortEdge", doc_duplexflipshortedge},
+ {"DuplexFlipLongEdge", doc_duplexfliplongedge},
+ {NULL, 0}
+};
+
+
+
+static const pdc_keyconn pdf_pdfa_keylist[] =
+{
+ {NULL, 0}
+};
+
+
+
+static const pdc_keyconn pdf_pdfx_keylist[] =
+{
+ {NULL, 0}
+};
+
+
+/* configurable flush points */
+
+static const pdc_keyconn pdf_flush_keylist[] =
+{
+ {"none", pdc_flush_none},
+ {"page", pdc_flush_page},
+ {"content", pdc_flush_content},
+ {"heavy", pdc_flush_heavy},
+ {NULL, 0}
+};
+
+static const pdc_keyconn pl_pwencoding_keylist[] =
+{
+ {"ebcdic", pdc_ebcdic},
+ {"ebcdic_37", pdc_ebcdic_37},
+ {"ebcdic_winansi", pdc_ebcdic_winansi},
+ {"pdfdoc", pdc_pdfdoc},
+ {"winansi", pdc_winansi},
+ {"macroman", pdc_macroman_apple},
+ {NULL, 0}
+};
+
+#define PDF_MAXPW 0
+static const pdc_keyconn pdc_permissions_keylist[] =
+{
+ {NULL, 0}
+};
+
+#define PDF_PDFA_FLAG PDC_OPT_UNSUPP
+
+#define PDF_SECURITY_FLAG PDC_OPT_UNSUPP
+
+#define PDF_LINEARIZE_FLAG PDC_OPT_UNSUPP
+
+#define PDF_ICC_FLAG PDC_OPT_UNSUPP
+
+#define PDF_TAGGED_FLAG PDC_OPT_UNSUPP
+
+#define PDF_METADATA_FLAG PDC_OPT_UNSUPP
+
+#define PDF_UPDATE_FLAG PDC_OPT_UNSUPP
+
+#define PDF_DOCUMENT_OPTIONS1 \
+\
+ {"pdfa", pdc_keywordlist, PDF_PDFA_FLAG, 1, 1, \
+ 0.0, 0.0, pdf_pdfa_keylist}, \
+\
+ {"pdfx", pdc_keywordlist, PDF_ICC_FLAG, 1, 1, \
+ 0.0, 0.0, pdf_pdfx_keylist}, \
+\
+ {"compatibility", pdc_keywordlist, PDC_OPT_IGNOREIF1, 1, 1, \
+ 0.0, 0.0, pdf_compatibility_keylist}, \
+\
+ {"flush", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, 0.0, pdf_flush_keylist}, \
+\
+ {"passwordencoding", pdc_keywordlist, PDF_SECURITY_FLAG, 1, 1, \
+ 0.0, 0.0, pl_pwencoding_keylist}, \
+\
+ {"attachmentpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \
+ 0.0, PDF_MAXPW, NULL}, \
+\
+ {"masterpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \
+ 0.0, PDF_MAXPW, NULL}, \
+\
+ {"userpassword", pdc_stringlist, PDF_SECURITY_FLAG, 1, 1, \
+ 0.0, PDF_MAXPW, NULL}, \
+\
+ {"permissions", pdc_keywordlist, \
+ PDF_SECURITY_FLAG | PDC_OPT_BUILDOR | PDC_OPT_DUPORIGVAL, 1, 9,\
+ 0.0, 0.0, pdc_permissions_keylist}, \
+\
+ {"update", pdc_booleanlist, PDF_UPDATE_FLAG, 1, 1, \
+ 0.0, 0.0, NULL}, \
+\
+ {"tagged", pdc_booleanlist, PDF_TAGGED_FLAG, 1, 1, \
+ 0.0, 0.0, NULL}, \
+\
+ {"lang", pdc_stringlist, PDF_TAGGED_FLAG, 1, 1, \
+ 0.0, PDF_MAX_LANGCODE, NULL}, \
+\
+ {"search", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"groups", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
+ 0.0, PDF_MAX_NAMESTRING, NULL}, \
+\
+ {"optimize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \
+ 0.0, 0.0, NULL}, \
+\
+ {"linearize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \
+ 0.0, 0.0, NULL}, \
+\
+ {"inmemory", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1,\
+ 0.0, 0.0, NULL}, \
+\
+ {"tempdirname", pdc_stringlist, PDF_LINEARIZE_FLAG, 1, 1, \
+ 4.0, 400.0, NULL}, \
+
+
+#if defined(MVS) || defined(MVS_TEST)
+#define PDF_DOCUMENT_OPTIONS10 \
+\
+ {"recordsize", pdc_integerlist, PDF_LINEARIZE_FLAG, 1, 1, \
+ 0.0, 32768.0, NULL}, \
+\
+ {"tempfilenames", pdc_stringlist, PDF_LINEARIZE_FLAG, 2, 2, \
+ 4.0, 400.0, NULL}, \
+
+#endif
+
+
+#define PDF_DOCUMENT_OPTIONS2 \
+\
+ {"hypertextencoding", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDF_MAX_NAMESTRING, NULL}, \
+\
+ {"moddate", pdc_booleanlist, PDC_OPT_NONE, 1, 1,\
+ 0.0, 0.0, NULL}, \
+\
+ {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"labels", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
+ 0.0, PDC_USHRT_MAX, NULL}, \
+\
+ {"openmode", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, 0.0, pdf_openmode_keylist}, \
+\
+ {"pagelayout", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, 0.0, pdf_pagelayout_pdfkeylist}, \
+\
+ {"uri", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"viewerpreferences", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
+ 0.0, PDC_USHRT_MAX, NULL}, \
+\
+ {"autoxmp", pdc_booleanlist, PDF_METADATA_FLAG, 1, 1, \
+ 0.0, 0.0, NULL}, \
+\
+ {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \
+ 0.0, PDC_INT_MAX, NULL}, \
+\
+ {"attachments", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
+ 0.0, PDC_INT_MAX, NULL}, \
+
+
+/* document struct */
+
+struct pdf_document_s
+{
+ int compatibility; /* PDF version number * 10 */
+ pdc_flush_state flush; /* output flushing points */
+
+
+
+
+
+
+ pdc_bool moddate; /* modified date will be created */
+ char lang[PDF_MAX_LANGCODE + 1]; /* default natural language */
+ char *action; /* document actions */
+ pdf_dest *dest; /* destination as open action */
+ char *uri; /* document's base url */
+ char *viewerpreferences; /* option list with viewer preferences */
+ pdc_bool writevpdict; /* viewer preferences dictionary
+ * must be written */
+ pdf_openmode openmode; /* document open mode */
+ pdf_pagelayout pagelayout; /* page layout within document */
+
+ char *searchindexname; /* file name for search index */
+ char *searchindextype; /* type for search index */
+
+ pdf_attachments *attachments; /* temporarily file attachments */
+ int nattachs; /* number of file attachments */
+
+
+ char *filename; /* file name of document */
+ size_t (*writeproc)(PDF *p, void *data, size_t size);
+ /* output procedure */
+ FILE *fp; /* file id - deprecated */
+ int len; /* length of custom */
+};
+
+static pdf_document *
+pdf_init_get_document(PDF *p)
+{
+ static const char fn[] = "pdf_init_get_document";
+
+ if (p->document == NULL)
+ {
+ pdf_document *doc = (pdf_document *)
+ pdc_malloc(p->pdc, sizeof(pdf_document), fn);
+
+ doc->compatibility = PDF_DEF_COMPATIBILITY;
+ doc->flush = pdc_flush_page;
+
+
+
+
+
+
+ doc->moddate = pdc_false;
+ doc->lang[0] = 0;
+ doc->action = NULL;
+ doc->dest = NULL;
+ doc->uri = NULL;
+ doc->viewerpreferences = NULL;
+ doc->writevpdict = pdc_false;
+ doc->openmode = open_auto;
+ doc->pagelayout = layout_default;
+
+ doc->searchindexname = NULL;
+ doc->searchindextype = NULL;
+
+ doc->attachments = NULL;
+ doc->nattachs = 0;
+
+
+ doc->fp = NULL;
+ doc->filename = NULL;
+ doc->writeproc = NULL;
+ doc->len = 0;
+
+ p->document = doc;
+ }
+
+ return p->document;
+}
+
+static void
+pdf_cleanup_document_internal(PDF *p)
+{
+ pdf_document *doc = (pdf_document *) p->document;
+
+ if (doc)
+ {
+ pdf_cleanup_destination(p, doc->dest);
+ doc->dest = NULL;
+
+ if (doc->action)
+ {
+ pdc_free(p->pdc, doc->action);
+ doc->action = NULL;
+ }
+
+ if (doc->uri)
+ {
+ pdc_free(p->pdc, doc->uri);
+ doc->uri = NULL;
+ }
+
+ if (doc->viewerpreferences)
+ {
+ pdc_free(p->pdc, doc->viewerpreferences);
+ doc->viewerpreferences = NULL;
+ }
+
+
+
+
+ if (doc->searchindexname)
+ {
+ pdc_free(p->pdc, doc->searchindexname);
+ doc->searchindexname = NULL;
+ }
+
+ if (doc->searchindextype)
+ {
+ pdc_free(p->pdc, doc->searchindextype);
+ doc->searchindextype = NULL;
+ }
+
+ if (doc->filename)
+ {
+ pdc_free(p->pdc, doc->filename);
+ doc->filename = NULL;
+ }
+
+ pdc_free(p->pdc, doc);
+ p->document = NULL;
+ }
+}
+
+
+/* ---------------------------- PDFA / PDFX -------------------------- */
+
+
+
+void
+pdf_fix_openmode(PDF *p)
+{
+ pdf_document *doc = pdf_init_get_document(p);
+
+ if (doc->openmode == open_auto)
+ doc->openmode = open_bookmarks;
+}
+
+
+
+
+
+/* ------------------------- viewerpreferences ----------------------- */
+
+static const pdc_defopt pdf_viewerpreferences_options[] =
+{
+ {"centerwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"direction", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_textdirection_pdfkeylist},
+
+ {"displaydoctitle", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"fitwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"hidemenubar", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"hidetoolbar", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"hidewindowui", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0, NULL},
+
+ {"nonfullscreenpagemode", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_nonfullscreen_keylist},
+
+ {"viewarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_usebox_keylist},
+
+ {"viewclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_usebox_keylist},
+
+ {"printarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_usebox_keylist},
+
+ {"printclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
+ 0.0, 0.0, pdf_usebox_keylist},
+
+ {"printscaling", pdc_keywordlist, PDC_OPT_PDC_1_6, 1, 1,
+ 0.0, 0.0, pdf_printscaling_pdfkeylist},
+
+ {"duplex", pdc_keywordlist, PDC_OPT_PDC_1_7, 1, 1,
+ 0.0, 0.0, pdf_duplex_pdfkeylist},
+
+ {"picktraybypdfsize", pdc_booleanlist, PDC_OPT_PDC_1_7, 1, 1,
+ 0.0, 0, NULL},
+
+ {"printpagerange", pdc_integerlist, PDC_OPT_PDC_1_7 | PDC_OPT_EVENNUM,
+ 1, PDC_USHRT_MAX, 1.0, PDC_INT_MAX, NULL}, \
+
+ {"numcopies", pdc_integerlist, PDC_OPT_PDC_1_7, 1, 1, \
+ 1.0, 5.0, NULL}, \
+
+ PDC_OPT_TERMINATE
+};
+
+static int
+pdf_parse_and_write_viewerpreferences(PDF *p, const char *optlist,
+ pdc_bool output)
+{
+ pdc_resopt *resopts = NULL;
+ pdc_clientdata cdata;
+ char **strlist;
+ pdc_bool writevpdict = pdc_false;
+ pdc_bool flag;
+ int i, nv, inum;
+
+ /* parsing option list */
+ pdf_set_clientdata(p, &cdata);
+ resopts = pdc_parse_optionlist(p->pdc, optlist,
+ pdf_viewerpreferences_options, &cdata, pdc_true);
+
+ if (pdc_get_optvalues("hidetoolbar", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/HideToolbar true\n");
+ }
+
+ if (pdc_get_optvalues("hidemenubar", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/HideMenubar true\n");
+ }
+
+ if (pdc_get_optvalues("hidewindowui", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/HideWindowUI true\n");
+ }
+
+ if (pdc_get_optvalues("fitwindow", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/FitWindow true\n");
+ }
+
+ if (pdc_get_optvalues("centerwindow", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/CenterWindow true\n");
+ }
+
+ if (pdc_get_optvalues("displaydoctitle", resopts, &flag, NULL) && flag)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/DisplayDocTitle true\n");
+ }
+
+ if (pdc_get_optvalues("nonfullscreenpagemode", resopts, &inum, NULL) &&
+ inum != (int) open_none)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/NonFullScreenPageMode/%s\n",
+ pdc_get_keyword(inum, pdf_openmode_pdfkeylist));
+ }
+
+
+ if (pdc_get_optvalues("direction", resopts, &inum, NULL) &&
+ inum != (int) doc_l2r)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/Direction/%s\n",
+ pdc_get_keyword(inum, pdf_textdirection_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("viewarea", resopts, &inum, NULL) &&
+ inum != (int) pdc_pbox_crop)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/ViewArea%s\n",
+ pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("viewclip", resopts, &inum, NULL) &&
+ inum != (int) pdc_pbox_crop)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/ViewClip%s\n",
+ pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("printarea", resopts, &inum, NULL) &&
+ inum != (int) pdc_pbox_crop)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/PrintArea%s\n",
+ pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("printclip", resopts, &inum, NULL) &&
+ inum != (int) pdc_pbox_crop)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/PrintClip%s\n",
+ pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("printscaling", resopts, &inum, NULL) &&
+ inum != (int) doc_appdefault)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/PrintScaling/%s\n",
+ pdc_get_keyword(inum, pdf_printscaling_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("duplex", resopts, &inum, NULL) &&
+ inum != (int) doc_none)
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/Duplex/%s\n",
+ pdc_get_keyword(inum, pdf_duplex_pdfkeylist));
+ }
+
+ if (pdc_get_optvalues("picktraybypdfsize", resopts, &flag, NULL))
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/PickTrayByPDFSize %s\n",
+ PDC_BOOLSTR(flag));
+ }
+
+ nv = pdc_get_optvalues("printpagerange", resopts, NULL, &strlist);
+ if (nv)
+ {
+ writevpdict = pdc_true;
+ if (output)
+ {
+ int *prs = (int *) strlist;
+
+ pdc_printf(p->out, "/PrintPageRange");
+ pdc_begin_array(p->out);
+ for (i = 0; i < nv; i++)
+ pdc_printf(p->out, "%d ", prs[i]);
+ pdc_end_array(p->out);
+ }
+ }
+
+ if (pdc_get_optvalues("numcopies", resopts, &inum, NULL))
+ {
+ writevpdict = pdc_true;
+ if (output) pdc_printf(p->out, "/NumCopies %d\n", inum);
+ }
+
+ pdc_cleanup_optionlist(p->pdc, resopts);
+
+ return writevpdict;
+}
+
+
+/* ------------------------- search ----------------------- */
+
+static const pdc_defopt pdf_search_options[] =
+{
+ {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
+ 1.0, PDC_FILENAMELEN, NULL},
+
+ {"indextype", pdc_stringlist, PDC_OPT_NONE, 1, 1,
+ 0.0, PDF_MAX_NAMESTRING, NULL},
+
+ PDC_OPT_TERMINATE
+};
+
+static void
+pdf_parse_search_optlist(PDF *p, const char *optlist)
+{
+ pdf_document *doc = p->document;
+ pdc_resopt *resopts = NULL;
+
+ /* parsing option list */
+ resopts = pdc_parse_optionlist(p->pdc, optlist,
+ pdf_search_options, NULL, pdc_true);
+
+ if (pdc_get_optvalues("filename", resopts, NULL, NULL))
+ doc->searchindexname =
+ (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+
+ if (pdc_get_optvalues("indextype", resopts, NULL, NULL))
+ doc->searchindextype =
+ (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+ else
+ doc->searchindextype = pdc_strdup(p->pdc, "PDX");
+
+ pdc_cleanup_optionlist(p->pdc, resopts);
+}
+
+static void
+pdf_write_search_indexes(PDF *p)
+{
+ pdf_document *doc = p->document;
+
+ if (doc->searchindexname != NULL)
+ {
+ pdc_puts(p->out, "/Search");
+ pdc_begin_dict(p->out); /* Search */
+ pdc_puts(p->out, "/Indexes");
+ pdc_begin_array(p->out);
+ pdc_begin_dict(p->out); /* Indexes */
+ pdc_puts(p->out, "/Name");
+ pdc_printf(p->out, "/%s", doc->searchindextype);
+ pdc_puts(p->out, "/Index");
+ pdc_begin_dict(p->out); /* Index */
+ pdc_puts(p->out, "/Type/Filespec");
+ pdc_puts(p->out, "/F");
+ pdf_put_pdffilename(p, doc->searchindexname);
+ pdc_end_dict(p->out); /* Index */
+ pdc_end_dict(p->out); /* Indexes */
+ pdc_end_array(p->out);
+ pdc_end_dict(p->out); /* Search */
+ }
+}
+
+
+/* ---------------------- file attachements -------------------- */
+
+static void
+pdc_cleanup_attachments_tmp(void *opaque, void *mem)
+{
+ if (mem)
+ {
+ PDF *p = (PDF *) opaque;
+ pdf_document *doc = p->document;
+ int i;
+
+ if (doc != NULL)
+ {
+ for (i = 0; i < doc->nattachs; i++)
+ {
+ pdf_attachments *fat = &doc->attachments[i];
+
+ if (fat->filename != NULL)
+ pdc_free(p->pdc, fat->filename);
+ if (fat->name != NULL)
+ pdc_free(p->pdc, fat->name);
+ if (fat->description != NULL)
+ pdc_free(p->pdc, fat->description);
+ if (fat->mimetype != NULL)
+ pdc_free(p->pdc, fat->mimetype);
+ }
+
+ doc->attachments = NULL;
+ doc->nattachs = 0;
+ }
+ }
+}
+
+static const pdc_defopt pdf_attachments_options[] =
+{
+ {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
+ 1.0, PDC_FILENAMELEN, NULL},
+
+ {"description", pdc_stringlist, PDC_OPT_PDC_1_6, 1, 1,
+ 0.0, PDC_INT_MAX, NULL},
+
+ {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1,
+ 0.0, PDF_MAX_NAMESTRING, NULL},
+
+ {"mimetype", pdc_stringlist, PDC_OPT_NONE, 1, 1,
+ 0.0, PDF_MAX_NAMESTRING, NULL},
+
+ PDC_OPT_TERMINATE
+};
+
+static void
+pdf_parse_attachments_optlist(PDF *p, char **optlists, int ns,
+ pdc_encoding htenc, int htcp)
+{
+ static const char fn[] = "pdf_parse_attachments_optlist";
+ pdf_document *doc = p->document;
+ pdc_resopt *resopts = NULL;
+ pdc_clientdata cdata;
+ int i;
+
+ doc->attachments = (pdf_attachments *) pdc_malloc_tmp(p->pdc,
+ ns * sizeof(pdf_attachments), fn,
+ p, pdc_cleanup_attachments_tmp);
+ doc->nattachs = ns;
+
+ pdf_set_clientdata(p, &cdata);
+
+ for (i = 0; i < ns; i++)
+ {
+ pdf_attachments *fat = &doc->attachments[i];
+
+ fat->filename = NULL;
+ fat->name = NULL;
+ fat->description = NULL;
+ fat->mimetype = NULL;
+ fat->filesize = 0;
+ }
+
+ for (i = 0; i < ns; i++)
+ {
+ pdf_attachments *fat = &doc->attachments[i];
+
+ /* parsing option list */
+ resopts = pdc_parse_optionlist(p->pdc, optlists[i],
+ pdf_attachments_options, &cdata, pdc_true);
+
+ if (pdc_get_optvalues("filename", resopts, NULL, NULL))
+ fat->filename =
+ (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+
+ if (pdf_get_opt_textlist(p, "description", resopts, htenc, htcp,
+ pdc_true, NULL, &fat->description, NULL))
+ pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+
+ if (pdf_get_opt_textlist(p, "name", resopts, htenc, htcp,
+ pdc_true, NULL, &fat->name, NULL))
+ pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+
+ if (pdc_get_optvalues("mimetype", resopts, NULL, NULL))
+ fat->mimetype =
+ (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+
+ pdc_cleanup_optionlist(p->pdc, resopts);
+
+ fat->filesize = pdf_check_file(p, fat->filename, pdc_true);
+ }
+}
+
+static void
+pdf_write_attachments(PDF *p)
+{
+ static const char fn[] = "pdf_write_attachments";
+ pdf_document *doc = p->document;
+ pdc_id attachment_id, obj_id;
+ char *name;
+ int i;
+
+ for (i = 0; i < doc->nattachs; i++)
+ {
+ pdf_attachments *fat = &doc->attachments[i];
+
+ if (fat->filesize > 0)
+ {
+ /* create file specification dictionary */
+ attachment_id = pdc_begin_obj(p->out, PDC_NEW_ID);
+ pdc_begin_dict(p->out); /* FS dict */
+
+ pdc_puts(p->out, "/Type/Filespec\n");
+ pdc_printf(p->out, "/F");
+ pdf_put_pdffilename(p, fat->filename);
+ pdc_puts(p->out, "\n");
+
+ if (fat->description != NULL)
+ {
+ pdc_puts(p->out, "/Desc");
+ pdf_put_hypertext(p, fat->description);
+ pdc_puts(p->out, "\n");
+ }
+
+ obj_id = pdc_alloc_id(p->out);
+ pdc_puts(p->out, "/EF");
+ pdc_begin_dict(p->out);
+ pdc_objref(p->out, "/F", obj_id);
+ pdc_end_dict(p->out);
+
+ pdc_end_dict(p->out); /* FS dict */
+ pdc_end_obj(p->out);
+
+ /* embed file */
+ pdf_embed_file(p, obj_id, fat->filename, fat->mimetype,
+ fat->filesize);
+
+ /* insert name in tree */
+ if (fat->name == NULL)
+ name = pdc_strdup_ext(p->pdc, fat->filename, 0, fn);
+ else
+ name = pdc_strdup_ext(p->pdc, fat->name, 0, fn);
+ pdf_insert_name(p, name, names_embeddedfiles, attachment_id);
+ }
+ }
+}
+
+pdc_off_t
+pdf_check_file(PDF *p, const char *filename, pdc_bool verbose)
+{
+ pdc_off_t filesize = 0;
+ const char *qualifier = "attachment ";
+ pdc_file *fp;
+
+ fp = pdc_fsearch_fopen(p->pdc, filename, NULL, qualifier,
+ PDC_FILE_BINARY);
+ if (fp == NULL)
+ {
+ if (verbose)
+ pdc_error(p->pdc, -1, 0, 0, 0, 0);
+ }
+ else
+ {
+ filesize = pdc_file_size(fp);
+ pdc_fclose(fp);
+
+ if (filesize == 0)
+ {
+ pdc_set_errmsg(p->pdc, PDC_E_IO_FILE_EMPTY, qualifier, filename,
+ 0, 0);
+ if (verbose)
+ pdc_error(p->pdc, -1, 0, 0, 0, 0);
+ }
+ }
+
+ return filesize;
+}
+
+void
+pdf_embed_file(PDF *p, pdc_id obj_id, const char *filename,
+ const char *mimetype, pdc_off_t filesize)
+{
+ pdc_id length_id;
+ PDF_data_source src;
+
+ pdc_begin_obj(p->out, obj_id);
+ pdc_begin_dict(p->out); /* F dict */
+
+ pdc_puts(p->out, "/Type/EmbeddedFile\n");
+
+ if (mimetype && *mimetype)
+ {
+ pdc_puts(p->out, "/Subtype");
+ pdf_put_pdfname(p, mimetype);
+ pdc_puts(p->out, "\n");
+ }
+
+ pdc_puts(p->out, "/Params");
+ pdc_begin_dict(p->out); /* Params */
+ pdc_printf(p->out, "/Size %lld", filesize);
+ pdc_end_dict(p->out); /* Params */
+
+ if (pdc_get_compresslevel(p->out))
+ {
+ pdc_puts(p->out, "/Filter/FlateDecode\n");
+ }
+
+ length_id = pdc_alloc_id(p->out);
+ pdc_objref(p->out, "/Length", length_id);
+
+ pdc_end_dict(p->out); /* F dict */
+
+ /* write the file in the PDF */
+ src.private_data = (void *) filename;
+ src.init = pdf_data_source_file_init;
+ src.fill = pdf_data_source_file_fill;
+ src.terminate = pdf_data_source_file_terminate;
+ src.length = (long) 0;
+ src.offset = (long) 0;
+
+
+ pdf_copy_stream(p, &src, pdc_true);
+
+
+ pdc_end_obj(p->out);
+
+ pdc_put_pdfstreamlength(p->out, length_id);
+
+ if (p->flush & pdc_flush_content)
+ pdc_flush_stream(p->out);
+}
+
+
+/* ---------------------- linearize -------------------- */
+
+
+
+/* ------------------ document options ----------------- */
+
+static void
+pdf_get_document_common_options(PDF *p, pdc_resopt *resopts, int fcode)
+{
+ pdf_document *doc = p->document;
+ pdc_encoding htenc;
+ int htcp;
+ char **strlist;
+ int i, inum, ns;
+
+
+ htenc =
+ pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true);
+
+ if (pdc_get_optvalues("destination", resopts, NULL, &strlist))
+ {
+ if (doc->dest)
+ pdc_free(p->pdc, doc->dest);
+ doc->dest = pdf_parse_destination_optlist(p, strlist[0], 1,
+ pdf_openaction);
+ }
+ else
+ {
+ pdf_dest *dest = pdf_get_option_destname(p, resopts, htenc, htcp);
+ if (dest)
+ {
+ if (doc->dest)
+ pdc_free(p->pdc, doc->dest);
+ doc->dest = dest;
+ }
+ }
+
+ if (pdc_get_optvalues("action", resopts, NULL, NULL))
+ {
+ if (doc->action)
+ pdc_free(p->pdc, doc->action);
+ doc->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+ pdf_parse_and_write_actionlist(p, event_document, NULL, doc->action);
+ }
+
+ inum = pdc_get_optvalues("labels", resopts, NULL, &strlist);
+ for (i = 0; i < inum; i++)
+ pdf_set_pagelabel(p, strlist[i], fcode);
+
+ if (pdc_get_optvalues("openmode", resopts, &inum, NULL))
+ doc->openmode = (pdf_openmode) inum;
+ if (doc->openmode == open_attachments && p->compatibility < PDC_1_6)
+ pdc_error(p->pdc, PDC_E_OPT_VERSION, "openmode=attachments",
+ pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
+
+ if (pdc_get_optvalues("pagelayout", resopts, &inum, NULL))
+ doc->pagelayout = (pdf_pagelayout) inum;
+ if (p->compatibility < PDC_1_5)
+ {
+ if (doc->pagelayout == layout_twopageleft)
+ pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageLeft",
+ pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
+ if (doc->pagelayout == layout_twopageright)
+ pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageRight",
+ pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
+ }
+
+ if (pdc_get_optvalues("uri", resopts, NULL, NULL))
+ {
+ if (doc->uri)
+ pdc_free(p->pdc, doc->uri);
+ doc->uri = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+ }
+
+ if (pdc_get_optvalues("viewerpreferences", resopts, NULL, NULL))
+ {
+ if (doc->viewerpreferences)
+ pdc_free(p->pdc, doc->viewerpreferences);
+ doc->viewerpreferences =
+ (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
+ doc->writevpdict |=
+ pdf_parse_and_write_viewerpreferences(p, doc->viewerpreferences,
+ pdc_false);
+ }
+
+ if (pdc_get_optvalues("search", resopts, NULL, &strlist))
+ pdf_parse_search_optlist(p, strlist[0]);
+
+
+ pdc_get_optvalues("moddate", resopts, &doc->moddate, NULL);
+
+
+
+ ns = pdc_get_optvalues("attachments", resopts, NULL, &strlist);
+ if (ns)
+ pdf_parse_attachments_optlist(p, strlist, ns, htenc, htcp);
+}
+
+static const pdc_defopt pdf_begin_document_options[] =
+{
+ PDF_DOCUMENT_OPTIONS1
+#if defined(MVS) || defined(MVS_TEST)
+ PDF_DOCUMENT_OPTIONS10
+#endif
+ PDF_DOCUMENT_OPTIONS2
+ PDF_ERRORPOLICY_OPTION
+ PDC_OPT_TERMINATE
+};
+
+
+/*
+ * The external callback interface requires a PDF* as the first argument,
+ * while the internal interface uses pdc_output* and doesn't know about PDF*.
+ * We use a wrapper to bridge the gap, and store the PDF* within the
+ * pdc_output structure opaquely.
+ */
+
+static size_t
+writeproc_wrapper(pdc_output *out, void *data, size_t size)
+{
+ size_t ret;
+
+ PDF *p = (PDF *) pdc_get_opaque(out);
+
+ ret = (p->writeproc)(p, data, size);
+ pdc_logg_cond(p->pdc, 1, trc_api,
+ "/* writeproc(data[%p], %d)[%d] */\n", data, size, ret);
+ return ret;
+}
+
+
+
+/* ---------------------------- begin document -------------------------- */
+
+static int
+pdf_begin_document_internal(PDF *p, const char *optlist, pdc_bool callback)
+{
+ pdf_document *doc = p->document;
+ pdc_resopt *resopts = NULL;
+ char **groups = NULL;
+ int n_groups = 0;
+ pdc_bool verbose = p->debug[(int) 'o'];
+ pdc_outctl oc;
+
+ (void) callback;
+
+ verbose = pdf_get_errorpolicy(p, NULL, verbose);
+
+ /* parsing option list */
+ if (optlist && *optlist)
+ {
+ int inum;
+
+ resopts = pdc_parse_optionlist(p->pdc, optlist,
+ pdf_begin_document_options, NULL, pdc_true);
+
+ verbose = pdf_get_errorpolicy(p, resopts, verbose);
+
+ pdc_get_optvalues("compatibility", resopts, &doc->compatibility, NULL);
+
+ if (pdc_get_optvalues("flush", resopts, &inum, NULL))
+ doc->flush = (pdc_flush_state) inum;
+
+ pdc_get_optvalues("lang", resopts, doc->lang, NULL);
+
+
+
+
+
+
+
+
+ n_groups = pdc_get_optvalues("groups", resopts, NULL, &groups);
+ }
+
+ /* copy for easy access */
+ p->compatibility = doc->compatibility;
+ p->pdc->compatibility = doc->compatibility;
+ p->flush = doc->flush;
+
+
+
+
+
+ /*
+ * None of these functions must call pdc_alloc_id() or generate
+ * any output since the output machinery is not yet initialized!
+ */
+
+ pdf_init_pages(p, (const char **) groups, n_groups);
+
+ /* common options */
+ pdf_get_document_common_options(p, resopts, PDF_FC_BEGIN_DOCUMENT);
+
+
+ /* deprecated */
+ p->bookmark_dest = pdf_init_destination(p);
+
+ pdf_init_images(p);
+ pdf_init_xobjects(p);
+ pdf_init_fonts(p);
+ pdf_init_outlines(p);
+ pdf_init_annot_params(p);
+ pdf_init_colorspaces(p);
+ pdf_init_pattern(p);
+ pdf_init_shadings(p);
+ pdf_init_extgstates(p);
+
+
+
+
+
+ /* create document digest */
+ pdc_init_digest(p->out);
+
+ if (!p->pdc->ptfrun)
+ {
+ if (doc->fp)
+ pdc_update_digest(p->out, (pdc_byte *) doc->fp, doc->len);
+ else if (doc->writeproc)
+ pdc_update_digest(p->out, (pdc_byte *) &doc->writeproc, doc->len);
+ else if (doc->filename)
+ pdc_update_digest(p->out, (pdc_byte *) doc->filename, doc->len);
+ }
+
+ pdf_feed_digest_info(p);
+
+ if (!p->pdc->ptfrun)
+ {
+ pdc_update_digest(p->out, (pdc_byte *) &p, sizeof(PDF*));
+ pdc_update_digest(p->out, (pdc_byte *) p, sizeof(PDF));
+ }
+
+
+ pdc_finish_digest(p->out, !p->pdc->ptfrun);
+
+ /* preparing output struct */
+ pdc_init_outctl(&oc);
+ oc.flush = doc->flush;
+
+ if (doc->fp)
+ oc.fp = doc->fp;
+ else if (doc->writeproc)
+ {
+ oc.writeproc = writeproc_wrapper;
+ p->writeproc = doc->writeproc;
+ }
+ else if (doc->filename)
+ oc.filename = doc->filename;
+ else
+ oc.filename = "";
+
+
+
+ if (!pdc_init_output((void *) p, p->out, doc->compatibility, &oc))
+ {
+ if (oc.filename && *oc.filename)
+ {
+ pdc_set_fopen_errmsg(p->pdc,
+ pdc_get_fopen_errnum(p->pdc, PDC_E_IO_WROPEN), "PDF ",
+ pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, oc.filename));
+
+ if (verbose)
+ pdc_error(p->pdc, -1, 0, 0, 0, 0);
+ }
+
+ pdf_cleanup_document_internal(p);
+ return -1;
+ }
+
+ /* Write the constant /ProcSet array once at the beginning */
+ p->procset_id = pdc_begin_obj(p->out, PDC_NEW_ID);
+ pdc_puts(p->out, "[/PDF/ImageB/ImageC/ImageI/Text]\n");
+ pdc_end_obj(p->out);
+
+ pdf_init_pages2(p);
+
+ pdf_write_attachments(p);
+
+ return 1;
+}
+
+#if defined(_MSC_VER) && defined(_MANAGED)
+#pragma unmanaged
+#endif
+int
+pdf__begin_document(PDF *p, const char *filename, int len, const char *optlist)
+{
+ pdf_document *doc;
+ pdc_bool verbose = p->debug[(int) 'o'];
+ int retval;
+
+ verbose = pdf_get_errorpolicy(p, NULL, verbose);
+
+
+ doc = pdf_init_get_document(p);
+
+ /* file ID or filename */
+ if (len == -1)
+ {
+ FILE *fp = (FILE *) filename;
+
+ /*
+ * It is the callers responsibility to open the file in binary mode,
+ * but it doesn't hurt to make sure it really is.
+ * The Intel version of the Metrowerks compiler doesn't have setmode().
+ */
+#if !defined(__MWERKS__) && (defined(WIN32) || defined(OS2))
+#if defined WINCE
+ _setmode(fileno(fp), _O_BINARY);
+#else
+ setmode(fileno(fp), O_BINARY);
+#endif
+#endif
+
+ doc->fp = fp;
+ doc->len = sizeof(FILE);
+ }
+ else if (filename && (*filename || len > 0))
+ {
+ filename = pdf_convert_filename(p, filename, len, "filename",
+ PDC_CONV_WITHBOM);
+ doc->filename = pdc_strdup(p->pdc, filename);
+ doc->len = (int) strlen(doc->filename);
+ }
+
+ retval = pdf_begin_document_internal(p, optlist, pdc_false);
+
+ if (retval > -1)
+ PDF_SET_STATE(p, pdf_state_document);
+
+ if (!p->pdc->smokerun)
+ pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n");
+
+ return retval;
+}
+#if defined(_MSC_VER) && defined(_MANAGED)
+#pragma managed
+#endif
+
+void
+pdf__begin_document_callback(PDF *p,
+ size_t (*i_writeproc)(PDF *p, void *data, size_t size), const char *optlist)
+{
+ size_t (*writeproc)(PDF *, void *, size_t) = i_writeproc;
+ pdf_document *doc;
+
+ if (writeproc == NULL)
+ pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "writeproc", 0, 0, 0);
+
+ doc = pdf_init_get_document(p);
+
+ /* initializing and opening the document */
+ doc->writeproc = writeproc;
+ doc->len = sizeof(writeproc);
+
+ (void) pdf_begin_document_internal(p, optlist, pdc_true);
+
+ PDF_SET_STATE(p, pdf_state_document);
+
+ if (!p->pdc->smokerun)
+ pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n");
+}
+
+/* ----------------------------- name tree ----------------------------- */
+
+struct pdf_name_s
+{
+ pdc_id obj_id; /* id of this name object */
+ char * name; /* name string */
+ pdf_nametree_type type; /* name tree type */
+};
+
+static void
+pdf_cleanup_names(PDF *p)
+{
+ int i;
+
+ if (p->names == NULL)
+ return;
+
+ for (i = 0; i < p->names_number; i++)
+ {
+ pdc_free(p->pdc, p->names[i].name);
+ }
+
+ pdc_free(p->pdc, p->names);
+ p->names_number = 0;
+ p->names = NULL;
+}
+
+void
+pdf_insert_name(PDF *p, const char *name, pdf_nametree_type type, pdc_id obj_id)
+{
+ static const char fn[] = "pdf_insert_name";
+ int i;
+
+ if (p->names == NULL || p->names_number == p->names_capacity)
+ {
+ if (p->names == NULL)
+ {
+ p->names_number = 0;
+ p->names_capacity = NAMES_CHUNKSIZE;
+ p->names = (pdf_name *) pdc_malloc(p->pdc,
+ sizeof(pdf_name) * p->names_capacity, fn);
+ }
+ else
+ {
+ p->names_capacity *= 2;
+ p->names = (pdf_name *) pdc_realloc(p->pdc, p->names,
+ sizeof(pdf_name) * p->names_capacity, fn);
+ }
+ for (i = p->names_number; i < p->names_capacity; i++)
+ {
+ p->names[i].obj_id = PDC_BAD_ID;
+ p->names[i].name = NULL;
+ p->names[i].type = names_undef;
+ }
+ }
+
+ /* check identity */
+ for (i = 0; i < p->names_number; i++)
+ {
+ if (p->names[i].type == type && !strcmp(p->names[i].name, name))
+ {
+ pdc_free(p->pdc, p->names[i].name);
+ p->names[i].name = (char *) name;
+ return;
+ }
+ }
+
+ p->names[i].obj_id = obj_id;
+ p->names[i].name = (char *) name;
+ p->names[i].type = type;
+ p->names_number++;
+}
+
+pdc_id
+pdf_get_id_from_nametree(PDF *p, pdf_nametree_type type, const char *name)
+{
+ int i;
+
+ for (i = 0; i < p->names_number; i++)
+ {
+ if (p->names[i].type == type && !strcmp(name, p->names[i].name))
+ return p->names[i].obj_id;
+ }
+
+ return PDC_BAD_ID;
+}
+
+static pdc_id
+pdf_write_names(PDF *p, pdf_nametree_type type)
+{
+ pdc_id ret = PDC_BAD_ID;
+ int i, ibeg = -1, iend = 0;
+
+ for (i = 0; i < p->names_number; i++)
+ {
+ if (p->names[i].type == type)
+ {
+ if (ibeg == -1)
+ ibeg = i;
+ iend = i;
+ }
+ }
+
+ if (ibeg > -1)
+ {
+ ret = pdc_begin_obj(p->out, PDC_NEW_ID); /* Names object */
+
+ pdc_begin_dict(p->out); /* Node dict */
+
+ /*
+ * Because we have only the 1 tree - the root tree
+ * the /Limits entry is not allowed (see chapter 3.8.5).
+ *
+ pdc_puts(p->out, "/Limits");
+ pdc_begin_array(p->out);
+ pdf_put_hypertext(p, p->names[ibeg].name);
+ pdf_put_hypertext(p, p->names[iend].name);
+ pdc_end_array(p->out);
+ */
+
+ pdc_puts(p->out, "/Names");
+ pdc_begin_array(p->out);
+
+ for (i = ibeg; i <= iend; i++)
+ {
+ if (p->names[i].type == type)
+ {
+ pdf_put_hypertext(p, p->names[i].name);
+ pdc_objref(p->out, "", p->names[i].obj_id);
+ }
+ }
+
+ pdc_end_array(p->out);
+
+ pdc_end_dict(p->out); /* Node dict */
+
+ pdc_end_obj(p->out); /* Names object */
+
+ }
+ return ret;
+}
+
+static int
+name_compare( const void* a, const void* b)
+{
+ pdf_name *p1 = (pdf_name *) a;
+ pdf_name *p2 = (pdf_name *) b;
+
+ return strcmp(p1->name, p2->name);
+}
+
+/* ---------------------------- write document -------------------------- */
+
+static pdc_id
+pdf_write_pages_and_catalog(PDF *p, pdc_id orig_root_id)
+{
+ pdf_document *doc = p->document;
+ pdc_bool openact = pdc_false;
+ pdc_bool forpdfa = pdc_false;
+ pdc_id act_idlist[PDF_MAX_EVENTS];
+ pdc_id root_id = PDC_BAD_ID;
+ pdc_id names_dests_id = PDC_BAD_ID;
+ pdc_id names_javascript_id = PDC_BAD_ID;
+ pdc_id names_ap_id = PDC_BAD_ID;
+ pdc_id names_embeddedfiles_id = PDC_BAD_ID;
+ pdc_id outintents1_id = PDC_BAD_ID;
+ pdc_id outintents2_id = PDC_BAD_ID;
+
+ pdc_id pages_id = pdf_write_pages_tree(p);
+ pdc_id labels_id = pdf_write_pagelabels(p);
+
+
+
+ (void) orig_root_id;
+
+ /* name tree dictionaries */
+ if (p->names_number)
+ {
+
+ qsort(p->names, (size_t) p->names_number, sizeof(pdf_name),
+ name_compare);
+
+
+ names_dests_id = pdf_write_names(p, names_dests);
+ names_javascript_id = pdf_write_names(p, names_javascript);
+ names_ap_id = pdf_write_names(p, names_ap);
+ names_embeddedfiles_id = pdf_write_names(p, names_embeddedfiles);
+ }
+
+
+ (void) forpdfa;
+
+
+
+
+ /* write action objects */
+ if (doc->action)
+ pdf_parse_and_write_actionlist(p, event_document, act_idlist,
+ (const char *) doc->action);
+
+ root_id = pdc_begin_obj(p->out, PDC_NEW_ID); /* Catalog */
+ pdc_begin_dict(p->out);
+ pdc_puts(p->out, "/Type/Catalog\n");
+
+ pdc_objref(p->out, "/Pages", pages_id); /* Pages object */
+
+
+ if (labels_id != PDC_BAD_ID)
+ {
+ pdc_objref(p->out, "/PageLabels", labels_id);
+ }
+
+ if (p->names_number)
+ {
+ pdc_printf(p->out, "/Names");
+ pdc_begin_dict(p->out); /* Names */
+
+ if (names_dests_id != PDC_BAD_ID)
+ pdc_objref(p->out, "/Dests", names_dests_id);
+ if (names_javascript_id != PDC_BAD_ID)
+ pdc_objref(p->out, "/JavaScript", names_javascript_id);
+ if (names_ap_id != PDC_BAD_ID)
+ pdc_objref(p->out, "/AP", names_ap_id);
+ if (names_embeddedfiles_id != PDC_BAD_ID)
+ pdc_objref(p->out, "/EmbeddedFiles", names_embeddedfiles_id);
+
+ pdc_end_dict(p->out); /* Names */
+ }
+
+ if (doc->writevpdict)
+ {
+ pdc_printf(p->out, "/ViewerPreferences\n");
+ pdc_begin_dict(p->out); /* ViewerPreferences */
+ pdf_parse_and_write_viewerpreferences(p,
+ doc->viewerpreferences, pdc_true);
+ pdc_end_dict(p->out); /* ViewerPreferences */
+ }
+
+ if (doc->pagelayout != layout_default)
+ pdc_printf(p->out, "/PageLayout/%s\n",
+ pdc_get_keyword(doc->pagelayout, pdf_pagelayout_pdfkeylist));
+
+ if (doc->openmode != open_auto && doc->openmode != open_none)
+ pdc_printf(p->out, "/PageMode/%s\n",
+ pdc_get_keyword(doc->openmode, pdf_openmode_pdfkeylist));
+
+ pdf_write_outline_root(p); /* /Outlines */
+
+ if (doc->action) /* /AA */
+ openact = pdf_write_action_entries(p, event_document, act_idlist);
+
+ if (doc->dest && !openact)
+ {
+ pdc_puts(p->out, "/OpenAction");
+ pdf_write_destination(p, doc->dest);
+ }
+
+ if (doc->uri)
+ {
+ pdc_puts(p->out, "/URI");
+ pdc_begin_dict(p->out);
+ pdc_printf(p->out, "/Base");
+ pdf_put_hypertext(p, doc->uri);
+ pdc_end_dict(p->out);
+ }
+
+
+ if (doc->lang[0])
+ {
+ pdc_puts(p->out, "/Lang");
+ pdf_put_hypertext(p, doc->lang);
+ pdc_puts(p->out, "\n");
+ }
+
+ /* /StructTreeRoot /MarkInfo */
+
+ /* /OCProperties */
+
+ if (outintents1_id != PDC_BAD_ID || outintents2_id != PDC_BAD_ID)
+ {
+ pdc_puts(p->out, "/OutputIntents");
+ pdc_begin_array(p->out);
+ if (outintents1_id != PDC_BAD_ID)
+ pdc_objref(p->out, "", outintents1_id);
+ if (outintents2_id != PDC_BAD_ID)
+ pdc_objref(p->out, "", outintents2_id);
+ pdc_end_array(p->out);
+ }
+
+ /* /Search */
+ pdf_write_search_indexes(p);
+
+ /* /Metadata */
+
+ /* not supported: /Threads /PieceInfo /Perms /Legal */
+
+ pdc_end_dict(p->out); /* Catalog */
+ pdc_end_obj(p->out);
+
+ return root_id;
+}
+
+
+static void
+pdf_write_document(PDF *p)
+{
+ if (PDF_GET_STATE(p) != pdf_state_error)
+ {
+ pdf_document *doc = p->document;
+ pdc_id info_id = PDC_BAD_ID;
+ pdc_id root_id = PDC_BAD_ID;
+
+ if (pdf_last_page(p) == 0)
+ pdc_error(p->pdc, PDF_E_DOC_EMPTY, 0, 0, 0, 0);
+
+ pdf_write_attachments(p);
+
+
+ /* Write all pending document information up to xref table + trailer */
+ info_id = pdf_write_info(p, doc->moddate);
+
+ pdf_write_doc_fonts(p); /* font objects */
+ pdf_write_doc_colorspaces(p); /* color space resources */
+ pdf_write_doc_extgstates(p); /* ExtGState resources */
+ root_id = pdf_write_pages_and_catalog(p, root_id);
+ pdf_write_outlines(p);
+ pdc_write_xref(p->out);
+
+ pdc_write_trailer(p->out, info_id, root_id, 0, -1, -1, -1);
+ }
+
+ pdc_close_output(p->out);
+}
+
+/* ------------------------------ end document ---------------------------- */
+
+void
+pdf_cleanup_document(PDF *p)
+{
+ if (PDF_GET_STATE(p) != pdf_state_object)
+ {
+ /* Don't call pdc_cleanup_output() here because we may still need
+ * the buffer contents for pdf__get_buffer() after pdf__end_document().
+ */
+
+ pdf_delete_actions(p);
+
+ pdf_cleanup_destination(p, p->bookmark_dest); /* deprecated */
+ pdf_cleanup_pages(p);
+ pdf_cleanup_document_internal(p);
+ pdf_cleanup_info(p);
+ pdf_cleanup_fonts(p);
+ pdf_cleanup_outlines(p);
+ pdf_cleanup_annot_params(p);
+ pdf_cleanup_names(p);
+ pdf_cleanup_colorspaces(p);
+ pdf_cleanup_pattern(p);
+ pdf_cleanup_shadings(p);
+ pdf_cleanup_images(p);
+ pdf_cleanup_xobjects(p);
+ pdf_cleanup_extgstates(p);
+
+
+
+
+
+
+
+
+
+ pdf_cleanup_stringlists(p);
+
+ PDF_SET_STATE(p, pdf_state_object);
+ }
+}
+
+static const pdc_defopt pdf_end_document_options[] =
+{
+ PDF_DOCUMENT_OPTIONS2
+ PDC_OPT_TERMINATE
+};
+
+void
+pdf__end_document(PDF *p, const char *optlist)
+{
+ pdf_document *doc;
+
+ /* check if there are any suspended pages left.
+ */
+ pdf_check_suspended_pages(p);
+
+ /* get document pointer */
+ doc = pdf_init_get_document(p);
+
+ if (optlist && *optlist)
+ {
+ pdc_resopt *resopts = NULL;
+ pdc_clientdata cdata;
+
+ /* parsing option list */
+ pdf_set_clientdata(p, &cdata);
+ resopts = pdc_parse_optionlist(p->pdc, optlist,
+ pdf_end_document_options, &cdata, pdc_true);
+
+ /* get options */
+ pdf_get_document_common_options(p, resopts, PDF_FC_END_DOCUMENT);
+
+ }
+
+ pdf_write_document(p);
+
+
+ pdf_cleanup_document(p);
+
+ if (!p->pdc->smokerun)
+ pdc_logg_cond(p->pdc, 1, trc_api, "[End document]\n\n");
+}
+
+const char *
+pdf__get_buffer(PDF *p, long *size)
+{
+ const char *ret;
+ pdc_off_t llsize;
+
+
+ ret = pdc_get_stream_contents(p->out, &llsize);
+
+ if (llsize > LONG_MAX)
+ pdc_error(p->pdc, PDF_E_DOC_GETBUF_2GB, 0, 0, 0, 0);
+
+ *size = (long) llsize;
+ return ret;
+}
+
+
+
+
+/*****************************************************************************/
+/** deprecated historical document functions **/
+/*****************************************************************************/
+
+void
+pdf_set_flush(PDF *p, const char *flush)
+{
+ if (p->pdc->binding != NULL && strcmp(p->pdc->binding, "C++"))
+ return;
+
+ if (flush != NULL && *flush)
+ {
+ int i = pdc_get_keycode_ci(flush, pdf_flush_keylist);
+ if (i != PDC_KEY_NOTFOUND)
+ {
+ pdf_document *doc = pdf_init_get_document(p);
+
+ doc->flush = (pdc_flush_state) i;
+ p->flush = doc->flush;
+ return;
+ }
+ pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, flush, "flush",
+ 0, 0);
+ }
+}
+
+void
+pdf_set_uri(PDF *p, const char *uri)
+{
+ pdf_document *doc = pdf_init_get_document(p);
+
+ if (doc->uri)
+ pdc_free(p->pdc, doc->uri);
+ doc->uri = pdc_strdup(p->pdc, uri);
+}
+
+
+void
+pdf_set_compatibility(PDF *p, const char *compatibility)
+{
+
+ if (compatibility != NULL && *compatibility)
+ {
+ int i = pdc_get_keycode_ci(compatibility, pdf_compatibility_keylist);
+ if (i != PDC_KEY_NOTFOUND)
+ {
+ pdf_document *doc = pdf_init_get_document(p);
+
+ p->compatibility = i;
+ doc->compatibility = i;
+ p->pdc->compatibility = i;
+ return;
+ }
+ pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, compatibility, "compatibility",
+ 0, 0);
+ }
+}
+
+void
+pdf_set_openaction(PDF *p, const char *openaction)
+{
+ pdf_document *doc = pdf_init_get_document(p);
+
+ if (openaction != NULL && *openaction)
+ {
+ pdf_cleanup_destination(p, doc->dest);
+ doc->dest = pdf_parse_destination_optlist(p, openaction, 1,
+ pdf_openaction);
+ }
+}
+
+void
+pdf_set_openmode(PDF *p, const char *openmode)
+{
+ int i;
+
+ if (openmode == NULL || !*openmode)
+ openmode = "none";
+
+ i = pdc_get_keycode_ci(openmode, pdf_openmode_keylist);
+ if (i != PDC_KEY_NOTFOUND)
+ {
+ pdf_document *doc = pdf_init_get_document(p);
+
+ doc->openmode = (pdf_openmode) i;
+ }
+ else
+ pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, openmode, "openmode", 0, 0);
+}
+
+void
+pdf_set_viewerpreference(PDF *p, const char *viewerpreference)
+{
+ static const char fn[] = "pdf_set_viewerpreference";
+ pdf_document *doc = pdf_init_get_document(p);
+ char *optlist;
+ size_t nb1 = 0, nb2 = 0;
+
+ if (doc->viewerpreferences)
+ nb1 = strlen(doc->viewerpreferences) * sizeof(char *);
+ nb2 = strlen(viewerpreference) * sizeof(char *);
+
+ optlist = (char *) pdc_malloc(p->pdc, nb1 + nb2 + 2, fn);
+ optlist[0] = 0;
+ if (doc->viewerpreferences)
+ {
+ strcat(optlist, doc->viewerpreferences);
+ strcat(optlist, " ");
+ }
+ strcat(optlist, viewerpreference);
+
+ if (doc->viewerpreferences)
+ pdc_free(p->pdc, doc->viewerpreferences);
+ doc->viewerpreferences = optlist;
+ doc->writevpdict |=
+ pdf_parse_and_write_viewerpreferences(p, optlist, pdc_false);
+}
+
+
+
+