diff options
Diffstat (limited to 'src/pdflib/pdflib/p_document.c')
-rw-r--r-- | src/pdflib/pdflib/p_document.c | 1939 |
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); +} + + + + |