/*---------------------------------------------------------------------------* | 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.2 2006-07-11 13:10:33 alex Exp $ * * PDFlib document related routines * */ #undef MVS_TEST #define P_DOCUMENT_C #include "p_intern.h" #include "p_font.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 #include #endif #define PDF_MAX_LANGCODE 8 /* Document open modes */ typedef enum { open_auto, open_none, open_bookmarks, open_thumbnails, open_fullscreen } pdf_openmode; static const pdc_keyconn pdf_openmode_keylist[] = { {"none", open_none}, {"bookmarks", open_bookmarks}, {"thumbnails", open_thumbnails}, {"fullscreen", open_fullscreen}, {NULL, 0} }; static const pdc_keyconn pdf_openmode_pdfkeylist[] = { {"UseNone", open_auto}, {"UseNone", open_none}, {"UseOutlines", open_bookmarks}, {"UseThumbs", open_thumbnails}, {"FullScreen", open_fullscreen}, {NULL, 0} }; /* Document page layout */ typedef enum { layout_default, layout_singlepage, layout_onecolumn, layout_twocolumnleft, layout_twocolumnright } pdf_pagelayout; static const pdc_keyconn pdf_pagelayout_pdfkeylist[] = { {"Default", layout_default}, {"SinglePage", layout_singlepage}, {"OneColumn", layout_onecolumn}, {"TwoColumnLeft", layout_twocolumnleft}, {"TwoColumnRight", layout_twocolumnright}, {NULL, 0} }; /* NonFullScreenPageMode */ static const pdc_keyconn pdf_nonfullscreen_keylist[] = { {"none", open_none}, {"bookmarks", open_bookmarks}, {"thumbnails", open_thumbnails}, {NULL, 0} }; /* Direction */ typedef enum { doc_l2r, doc_r2l } pdf_textdirection; static const pdc_keyconn pdf_textdirection_pdfkeylist[] = { {"L2R", doc_l2r}, {"R2L", doc_r2l}, {NULL, 0} }; /* compatibility */ static const pdc_keyconn pdf_compatibility_keylist[] = { {"1.3", PDC_1_3}, {"1.4", PDC_1_4}, {"1.5", PDC_1_5}, {"1.6", PDC_1_6}, {NULL, 0} }; static const pdc_keyconn pdf_pdfx_keylist[] = { {NULL, 0} }; /* configurable flush points */ static const pdc_keyconn pdf_flush_keylist[] = { {"none", pdf_flush_none}, {"page", pdf_flush_page}, {"content", pdf_flush_content}, {"heavy", pdf_flush_heavy}, {NULL, 0} }; static const pdc_keyconn pl_pwencoding_keylist[] = { {"ebcdic", pdc_ebcdic}, {"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_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_DOCUMENT_OPTIONS1 \ \ {"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}, \ \ {"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}, \ \ {"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, PDF_MAXSTRINGSIZE, NULL}, \ \ {"groups", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \ 0.0, PDF_MAX_NAMESTRING, 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, PDF_MAXSTRINGSIZE, NULL}, \ \ {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, \ 0.0, PDF_MAXSTRINGSIZE, NULL}, \ \ {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ 0.0, PDF_MAXSTRINGSIZE, 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, PDF_MAXSTRINGSIZE, NULL}, \ \ {"viewerpreferences", pdc_stringlist, PDC_OPT_NONE, 1, 1, \ 0.0, PDC_USHRT_MAX, NULL}, \ \ {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \ 0.0, PDF_MAXSTRINGSIZE, NULL}, \ /* document struct */ struct pdf_document_s { int compatibility; /* PDF version number * 10 */ pdf_flush_state flush; /* flush points for callback output */ 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 */ 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 = PDC_1_5; doc->flush = pdf_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->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; } } void pdf_fix_openmode(PDF *p) { pdf_document *doc = pdf_init_get_document(p); if (doc->openmode == open_auto) doc->openmode = open_bookmarks; } 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}, PDC_OPT_TERMINATE }; static int pdf_parse_and_write_viewerpreferences(PDF *p, const char *optlist, pdc_bool output) { pdc_resopt *resopts = NULL; pdc_bool writevpdict = pdc_false; pdc_bool flag; int inum; /* parsing option list */ resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_viewerpreferences_options, NULL, 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) use_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) use_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) use_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) use_crop) { writevpdict = pdc_true; if (output) pdc_printf(p->out, "/PrintClip%s\n", pdc_get_keyword(inum, pdf_usebox_pdfkeylist)); } pdc_cleanup_optionlist(p->pdc, resopts); return writevpdict; } static const pdc_defopt pdf_search_options[] = { {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1, 1.0, PDF_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_get_document_common_options(PDF *p, pdc_resopt *resopts, int fcode) { pdf_document *doc = p->document; pdc_encoding hypertextencoding; int codepage; char **strlist; int i, inum; pdc_get_optvalues("moddate", resopts, &doc->moddate, NULL); hypertextencoding = pdf_get_hypertextencoding_opt(p, resopts, &codepage, 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, pdc_true); } else { pdf_dest *dest = pdf_get_option_destname(p, resopts, hypertextencoding); 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 (pdc_get_optvalues("pagelayout", resopts, &inum, NULL)) doc->pagelayout = (pdf_pagelayout) inum; 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]); } static const pdc_defopt pdf_begin_document_options[] = { PDF_DOCUMENT_OPTIONS1 #if defined(MVS) || defined(MVS_TEST) PDF_DOCUMENT_OPTIONS10 #endif PDF_DOCUMENT_OPTIONS2 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_trace_protocol(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_outctl oc; /* parsing option list */ if (optlist && *optlist) { int inum; resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_begin_document_options, NULL, pdc_true); pdc_get_optvalues("compatibility", resopts, &doc->compatibility, NULL); if (pdc_get_optvalues("flush", resopts, &inum, NULL)) doc->flush = (pdf_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->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 (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 && !p->ptfrun) pdc_update_digest(p->out, (pdc_byte *) doc->filename, doc->len); pdf_feed_digest_info(p); if (!p->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->ptfrun); /* preparing output struct */ pdc_init_outctl(&oc); 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_ET_MAXSTRLEN, oc.filename)); if (p->debug[(int) 'o']) pdc_warning(p->pdc, -1, 0, 0, 0, 0); } 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); 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; int retval; 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_true); 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); 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); } /* ----------------------------- 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++; } 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 */ 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) { pdf_document *doc = p->document; pdc_bool openact = 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 pages_id = pdf_write_pages_tree(p); pdc_id labels_id = pdf_write_pagelabels(p); /* 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); } /* 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 object */ 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); 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 */ /* /Search */ 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 */ } /* 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_id root_id; if (pdf_last_page(p) == 0) pdc_error(p->pdc, PDF_E_DOC_EMPTY, 0, 0, 0, 0); /* 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); 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_cleanup_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; /* parsing option list */ resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_end_document_options, NULL, pdc_true); /* get options */ pdf_get_document_common_options(p, resopts, PDF_FC_END_DOCUMENT); } pdf_write_document(p); pdf_cleanup_document(p); } 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->binding != NULL && strcmp(p->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 = (pdf_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); doc->compatibility = p->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, pdc_true); } } 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); }