campo-sirio/pdf/pdflib/p_document.c
guy 429faed747 Patch level : 10.0
Files correlati     : pdflib
Ricompilazione Demo : [ ]
Commento            :
Aggiornata PDFlib


git-svn-id: svn://10.65.10.50/trunk@17433 c028cbd2-c16b-5b4b-a496-9718f37d4682
2008-10-20 14:35:00 +00:00

2046 lines
53 KiB
C
Executable File

/*---------------------------------------------------------------------------*
| 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.3 2008-10-20 14:34:15 guy Exp $
*
* PDFlib document related routines
*
*/
#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,
open_layers
}
pdf_openmode;
static const pdc_keyconn pdf_openmode_keylist[] =
{
{"none", open_none},
{"bookmarks", open_bookmarks},
{"thumbnails", open_thumbnails},
{"fullscreen", open_fullscreen},
{"attachments", open_attachments},
{"layers", open_layers},
{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},
{"UseOC", open_layers},
{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},
{"layers", open_layers},
{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 \
\
{"filemode", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
0.0, PDF_MAX_NAMESTRING, NULL}, \
\
{"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)
{
if (inum == (int) open_layers)
pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0);
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++)
/* because of bug #1623: -1 */
pdc_printf(p->out, "%d ", prs[i] - 1);
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,
pdc_encoding htenc, int htcp)
{
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 (pdf_get_opt_textlist(p, "filename", resopts, htenc, htcp,
pdc_true, NULL, &doc->searchindexname, NULL))
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);
if (p->compatibility >= PDC_1_7)
{
pdc_printf(p->out, "/UF");
pdf_put_hypertext(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 (pdf_get_opt_textlist(p, "filename", resopts, htenc, htcp,
pdc_true, NULL, &fat->filename, NULL))
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;
const char *basename;
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 */
/* see bug #1439 */
basename = pdc_file_strip_dirs(fat->filename);
pdc_puts(p->out, "/Type/Filespec\n");
pdc_printf(p->out, "/F");
pdf_put_pdffilename(p, basename);
pdc_puts(p->out, "\n");
if (p->compatibility >= PDC_1_7)
{
pdc_printf(p->out, "/UF");
pdf_put_hypertext(p, basename);
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, basename, 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_layers)
pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0);
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], htenc, htcp);
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 defined(MVS) || defined(MVS_TEST)
oc.fopenparams = doc->fopenparams;
#endif
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_RETHROW(p->pdc);
}
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(__BORLANDC__) && !defined(OS2)
_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;
}
#define PDF_TREE_LEAF_SIZE 32
static char *
pdf_get_numbered_name(PDF *p, pdf_nametree_type type, int ia, int *in, int nn)
{
int i, j = ia, n = 0;
for (i = ia; i < p->names_number; i++)
{
if (p->names[i].type == type)
{
n++;
if (n == nn)
{
if (in != NULL)
*in = i;
return p->names[i].name;
}
j = i;
}
}
return (in != NULL) ? NULL : p->names[j].name;
}
static pdc_id
pdf_write_names(PDF *p, pdf_nametree_type type)
{
static const char fn[] = "pdf_write_names";
pdc_id ret = PDC_BAD_ID;
int i, nnames = 0;
for (i = 0; i < p->names_number; i++)
{
if (p->names[i].type == type)
{
nnames++;
}
}
if (nnames)
{
char *name;
int nleafs, nnodes, ik, il, ia, nn;
pdc_id *idlist;
nnodes = nnames / PDF_TREE_LEAF_SIZE;
if (!nnodes)
nleafs = nnames;
else
nleafs = PDF_TREE_LEAF_SIZE;
if (nnames > nnodes * nleafs)
nnodes++;
idlist = (pdc_id *) pdc_malloc(p->pdc,
(size_t) (nnodes * sizeof(pdc_id)), fn);
for (i = 0; i < nnodes; i++)
idlist[i] = pdc_alloc_id(p->out);
ret = pdc_begin_obj(p->out, PDC_NEW_ID); /* Names object */
pdc_begin_dict(p->out);
pdc_puts(p->out, "/Kids");
pdc_begin_array(p->out);
for (i = 0; i < nnodes; i++)
pdc_objref_c(p->out, idlist[i]);
pdc_end_array(p->out);
pdc_end_dict(p->out);
pdc_end_obj(p->out); /* Names object */
ia = 0;
for (ik = 0; ik < nnodes; ik++)
{
pdc_begin_obj(p->out, idlist[ik]);
pdc_begin_dict(p->out);
pdc_puts(p->out, "/Limits");
pdc_begin_array(p->out);
name = pdf_get_numbered_name(p, type, ia, NULL, 1);
pdc_put_pdfstring(p->out, name, pdc_strlen(name));
nn = (ik == nnodes - 1) ? p->names_number : nleafs;
name = pdf_get_numbered_name(p, type, ia, NULL, nn);
pdc_put_pdfstring(p->out, name, pdc_strlen(name));
pdc_end_array(p->out);
pdc_puts(p->out, "/Names");
pdc_begin_array(p->out);
for (il = 0; il < nn; il++)
{
name = pdf_get_numbered_name(p, type, ia, &ia, 1);
if (name == NULL)
break;
pdc_put_pdfstring(p->out, name, pdc_strlen(name));
pdc_objref(p->out, "", p->names[ia].obj_id);
ia++;
}
pdc_end_array(p->out);
pdc_end_dict(p->out);
pdc_end_obj(p->out);
}
pdc_free(p->pdc, idlist);
}
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 pdc_wstrcmp(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)
{
char *name;
int i, outlen, inlen;
for (i = 0; i < p->names_number; i++)
{
inlen = strlen(p->names[i].name);
name = pdf_convert_pdfstring(p, p->names[i].name, inlen, &outlen);
if (name != p->names[i].name)
pdc_free(p->pdc, p->names[i].name);
p->names[i].name = name;
}
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)
{
pdf_cleanup_pages(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 */
p->bookmark_dest = NULL;
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);
}