1 /*---------------------------------------------------------------------------*
2  |              PDFlib - A library for generating PDF on the fly             |
3  +---------------------------------------------------------------------------+
4  | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
5  +---------------------------------------------------------------------------+
6  |                                                                           |
7  |    This software is subject to the PDFlib license. It is NOT in the       |
8  |    public domain. Extended versions and commercial licenses are           |
9  |    available, please check http://www.pdflib.com.                         |
10  |                                                                           |
11  *---------------------------------------------------------------------------*/
12 
13 /* $Id: p_document.c,v 1.174.2.60 2009/10/21 14:28:09 stm Exp $
14  *
15  * PDFlib document related routines
16  *
17  */
18 
19 
20 #define P_DOCUMENT_C
21 
22 /* For checking the beta expiration date */
23 #include <time.h>
24 
25 #include "p_intern.h"
26 #include "p_image.h"
27 #include "p_layer.h"
28 #include "p_page.h"
29 #include "p_tagged.h"
30 
31 
32 
33 
34 #include "pc_strconst.h"
35 
36 
37 #if (defined(WIN32) || defined(OS2)) && !defined(WINCE)
38 #include <fcntl.h>
39 #include <io.h>
40 #endif
41 
42 
43 /* file attachment structure */
44 typedef struct
45 {
46     char *filename;
47     char *name;
48     char *description;
49     char *mimetype;
50     pdc_off_t filesize;
51 }
52 pdf_attachments;
53 
54 #define PDF_MAX_LANGCODE  8
55 
56 /* Document open modes */
57 
58 typedef enum
59 {
60     open_auto,
61     open_none,
62     open_bookmarks,
63     open_thumbnails,
64     open_fullscreen,
65     open_attachments,
66     open_layers
67 }
68 pdf_openmode;
69 
70 static const pdc_keyconn pdf_openmode_keylist[] =
71 {
72     {"none",        open_none},
73     {"bookmarks",   open_bookmarks},
74     {"thumbnails",  open_thumbnails},
75     {"fullscreen",  open_fullscreen},
76     {"attachments", open_attachments},
77     {"layers",      open_layers},
78     {NULL, 0}
79 };
80 
81 static const pdc_keyconn pdf_openmode_pdfkeylist[] =
82 {
83     {"UseNone",        open_auto},
84     {"UseNone",        open_none},
85     {"UseOutlines",    open_bookmarks},
86     {"UseThumbs",      open_thumbnails},
87     {"FullScreen",     open_fullscreen},
88     {"UseAttachments", open_attachments},
89     {"UseOC",          open_layers},
90     {NULL, 0}
91 };
92 
93 
94 /* Document page layout */
95 
96 typedef enum
97 {
98     layout_default,
99     layout_singlepage,
100     layout_onecolumn,
101     layout_twocolumnleft,
102     layout_twocolumnright,
103     layout_twopageleft,
104     layout_twopageright
105 }
106 pdf_pagelayout;
107 
108 static const pdc_keyconn pdf_pagelayout_pdfkeylist[] =
109 {
110     {"Default",        layout_default},
111     {"SinglePage",     layout_singlepage},
112     {"OneColumn",      layout_onecolumn},
113     {"TwoColumnLeft",  layout_twocolumnleft},
114     {"TwoColumnRight", layout_twocolumnright},
115     {"TwoPageLeft",    layout_twopageleft},
116     {"TwoPageRight",   layout_twopageright},
117     {NULL, 0}
118 };
119 
120 
121 /* NonFullScreenPageMode */
122 
123 static const pdc_keyconn pdf_nonfullscreen_keylist[] =
124 {
125     {"none",        open_none},
126     {"bookmarks",   open_bookmarks},
127     {"thumbnails",  open_thumbnails},
128     {"layers",      open_layers},
129     {NULL, 0}
130 };
131 
132 typedef enum
133 {
134     doc_none,
135     doc_l2r,
136     doc_r2l,
137     doc_appdefault,
138     doc_simplex,
139     doc_duplexflipshortedge,
140     doc_duplexfliplongedge
141 }
142 pdf_viewerprefence;
143 
144 /* Direction */
145 
146 static const pdc_keyconn pdf_textdirection_pdfkeylist[] =
147 {
148     {"L2R",   doc_l2r},
149     {"R2L",   doc_r2l},
150     {NULL, 0}
151 };
152 
153 /* PrintScaling */
154 
155 static const pdc_keyconn pdf_printscaling_pdfkeylist[] =
156 {
157     {"None",        doc_none},
158     {"AppDefault",  doc_appdefault},
159     {NULL, 0}
160 };
161 
162 /* Duplex */
163 
164 static const pdc_keyconn pdf_duplex_pdfkeylist[] =
165 {
166     {"None",                doc_none},
167     {"Simplex",             doc_simplex},
168     {"DuplexFlipShortEdge", doc_duplexflipshortedge},
169     {"DuplexFlipLongEdge",  doc_duplexfliplongedge},
170     {NULL, 0}
171 };
172 
173 
174 
175 static const pdc_keyconn pdf_pdfa_keylist[] =
176 {
177     {NULL, 0}
178 };
179 
180 
181 
182 static const pdc_keyconn pdf_pdfx_keylist[] =
183 {
184     {NULL, 0}
185 };
186 
187 
188 /* configurable flush points */
189 
190 static const pdc_keyconn pdf_flush_keylist[] =
191 {
192     {"none",    pdc_flush_none},
193     {"page",    pdc_flush_page},
194     {"content", pdc_flush_content},
195     {"heavy",   pdc_flush_heavy},
196     {NULL, 0}
197 };
198 
199 static const pdc_keyconn pl_pwencoding_keylist[] =
200 {
201     {"ebcdic",          pdc_ebcdic},
202     {"ebcdic_37",       pdc_ebcdic_37},
203     {"ebcdic_winansi",  pdc_ebcdic_winansi},
204     {"pdfdoc",          pdc_pdfdoc},
205     {"winansi",         pdc_winansi},
206     {"macroman",        pdc_macroman_apple},
207     {NULL, 0}
208 };
209 
210 #define PDF_MAXPW 0
211 static const pdc_keyconn pdc_permissions_keylist[] =
212 {
213     {NULL, 0}
214 };
215 
216 #define PDF_PDFA_FLAG  PDC_OPT_UNSUPP
217 
218 #define PDF_SECURITY_FLAG  PDC_OPT_UNSUPP
219 
220 #define PDF_LINEARIZE_FLAG  PDC_OPT_UNSUPP
221 
222 #define PDF_ICC_FLAG  PDC_OPT_UNSUPP
223 
224 #define PDF_TAGGED_FLAG  PDC_OPT_UNSUPP
225 
226 #define PDF_METADATA_FLAG  PDC_OPT_UNSUPP
227 
228 #define PDF_UPDATE_FLAG  PDC_OPT_UNSUPP
229 
230 #define PDF_DOCUMENT_OPTIONS1 \
231 \
232     {"pdfa", pdc_keywordlist, PDF_PDFA_FLAG, 1, 1, \
233       0.0, 0.0, pdf_pdfa_keylist}, \
234 \
235     {"pdfx", pdc_keywordlist, PDF_ICC_FLAG, 1, 1, \
236       0.0, 0.0, pdf_pdfx_keylist}, \
237 \
238     {"compatibility", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
239       0.0, 0.0, pdf_compatibility_keylist}, \
240 \
241     {"flush", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
242       0.0, 0.0, pdf_flush_keylist}, \
243 \
244     {"passwordencoding", pdc_keywordlist, PDF_SECURITY_FLAG, 1, 1, \
245       0.0, 0.0, pl_pwencoding_keylist}, \
246 \
247     {"attachmentpassword", pdc_stringlist,  PDF_SECURITY_FLAG, 1, 1, \
248       0.0, PDF_MAXPW, NULL}, \
249 \
250     {"masterpassword", pdc_stringlist,  PDF_SECURITY_FLAG, 1, 1, \
251       0.0, PDF_MAXPW, NULL}, \
252 \
253     {"userpassword", pdc_stringlist,  PDF_SECURITY_FLAG, 1, 1, \
254       0.0, PDF_MAXPW, NULL}, \
255 \
256     {"permissions", pdc_keywordlist, \
257       PDF_SECURITY_FLAG | PDC_OPT_BUILDOR | PDC_OPT_DUPORIGVAL, 1, 9,\
258       0.0, 0.0, pdc_permissions_keylist}, \
259 \
260     {"update", pdc_booleanlist, PDF_UPDATE_FLAG, 1, 1, \
261       0.0, 0.0, NULL}, \
262 \
263     {"tagged", pdc_booleanlist, PDF_TAGGED_FLAG, 1, 1, \
264       0.0, 0.0, NULL}, \
265 \
266     {"lang", pdc_stringlist,  PDF_TAGGED_FLAG, 1, 1, \
267       0.0, PDF_MAX_LANGCODE, NULL}, \
268 \
269     {"search", pdc_stringlist,  PDC_OPT_NONE, 1, 1, \
270       0.0, PDC_INT_MAX, NULL}, \
271 \
272     {"groups", pdc_stringlist,  PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
273       0.0, PDF_MAX_NAMESTRING, NULL}, \
274 \
275     {"optimize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \
276       0.0, 0.0, NULL}, \
277 \
278     {"linearize", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1, \
279       0.0, 0.0, NULL}, \
280 \
281     {"inmemory", pdc_booleanlist, PDF_LINEARIZE_FLAG, 1, 1,\
282       0.0, 0.0, NULL}, \
283 \
284     {"tempdirname", pdc_stringlist,  PDF_LINEARIZE_FLAG, 1, 1, \
285       4.0, 400.0, NULL}, \
286 
287 #if defined(MVS) || defined(MVS_TEST)
288 #define PDF_DOCUMENT_OPTIONS10 \
289 \
290     {"filemode", pdc_stringlist,  PDC_OPT_NONE, 1, 1, \
291       0.0, PDF_MAX_NAMESTRING, NULL}, \
292 \
293     {"recordsize", pdc_integerlist, PDF_LINEARIZE_FLAG, 1, 1, \
294       0.0, 32768.0, NULL}, \
295 \
296     {"tempfilenames", pdc_stringlist,  PDF_LINEARIZE_FLAG, 2, 2, \
297       4.0, 400.0, NULL}, \
298 
299 #endif
300 
301 
302 #define PDF_DOCUMENT_OPTIONS2 \
303 \
304     {"hypertextencoding", pdc_stringlist,  PDC_OPT_NONE, 1, 1, \
305       0.0, PDF_MAX_NAMESTRING, NULL}, \
306 \
307     {"moddate", pdc_booleanlist, PDC_OPT_NONE, 1, 1,\
308       0.0, 0.0, NULL}, \
309 \
310     {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
311       0.0, PDC_INT_MAX, NULL}, \
312 \
313     {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1, \
314       0.0, PDC_INT_MAX, NULL}, \
315 \
316     {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
317       0.0, PDC_INT_MAX, NULL}, \
318 \
319     {"labels", pdc_stringlist,  PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
320       0.0, PDC_USHRT_MAX, NULL}, \
321 \
322     {"openmode", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
323       0.0, 0.0, pdf_openmode_keylist}, \
324 \
325     {"pagelayout", pdc_keywordlist, PDC_OPT_NONE, 1, 1, \
326       0.0, 0.0, pdf_pagelayout_pdfkeylist}, \
327 \
328     {"uri", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
329       0.0, PDC_INT_MAX, NULL}, \
330 \
331     {"viewerpreferences", pdc_stringlist, PDC_OPT_NONE, 1, 1, \
332       0.0, PDC_USHRT_MAX, NULL}, \
333 \
334     {"autoxmp", pdc_booleanlist, PDF_METADATA_FLAG, 1, 1, \
335       0.0, 0.0, NULL}, \
336 \
337     {"metadata", pdc_stringlist, PDF_METADATA_FLAG, 1, 1, \
338       0.0, PDC_INT_MAX, NULL}, \
339 \
340     {"attachments", pdc_stringlist, PDC_OPT_NONE, 1, PDC_USHRT_MAX, \
341       0.0, PDC_INT_MAX, NULL}, \
342 
343 
344 /* document struct */
345 
346 struct pdf_document_s
347 {
348     int compatibility;               /* PDF version number * 10 */
349     pdc_flush_state flush;           /* output flushing points */
350 
351 
352 
353 
354 
355 
356 #if defined(MVS) || defined(MVS_TEST)
357     char *fopenparams;               /* additional fopen() parameter string */
358     char **tempfilenames;            /* 2 temporary file names */
359 #endif
360 
361     pdc_bool moddate;                /* modified date will be created */
362     char lang[PDF_MAX_LANGCODE + 1]; /* default natural language */
363     char *action;                    /* document actions */
364     pdf_dest *dest;                  /* destination as open action */
365     char *uri;                       /* document's base url */
366     char *viewerpreferences;         /* option list with viewer preferences */
367     pdc_bool writevpdict;            /* viewer preferences dictionary
368                                       * must be written */
369     pdf_openmode openmode;           /* document open mode */
370     pdf_pagelayout pagelayout;       /* page layout within document */
371 
372     char *searchindexname;           /* file name for search index */
373     char *searchindextype;           /* type for search index */
374 
375     pdf_attachments *attachments;    /* temporarily file attachments */
376     int nattachs;                    /* number of file attachments */
377 
378 
379     char *filename;                  /* file name of document */
380     size_t (*writeproc)(PDF *p, void *data, size_t size);
381                                      /* output procedure */
382     FILE *fp;                        /* file id - deprecated */
383     int len;                         /* length of custom */
384 };
385 
386 static pdf_document *
pdf_init_get_document(PDF * p)387 pdf_init_get_document(PDF *p)
388 {
389     static const char fn[] = "pdf_init_get_document";
390 
391     if (p->document == NULL)
392     {
393         pdf_document *doc = (pdf_document *)
394                                 pdc_malloc(p->pdc, sizeof(pdf_document), fn);
395 
396         doc->compatibility = PDF_DEF_COMPATIBILITY;
397         doc->flush = pdc_flush_page;
398 
399 
400 
401 
402 
403 
404 #if defined(MVS) || defined(MVS_TEST)
405         doc->fopenparams = NULL;
406         doc->tempfilenames = NULL;
407 #endif
408 
409         doc->moddate = pdc_false;
410         doc->lang[0] = 0;
411         doc->action = NULL;
412         doc->dest = NULL;
413         doc->uri = NULL;
414         doc->viewerpreferences = NULL;
415         doc->writevpdict = pdc_false;
416         doc->openmode = open_auto;
417         doc->pagelayout = layout_default;
418 
419         doc->searchindexname = NULL;
420         doc->searchindextype = NULL;
421 
422         doc->attachments = NULL;
423         doc->nattachs = 0;
424 
425 
426         doc->fp = NULL;
427         doc->filename = NULL;
428         doc->writeproc = NULL;
429         doc->len = 0;
430 
431         p->document = doc;
432     }
433 
434     return p->document;
435 }
436 
437 static void
pdf_cleanup_document_internal(PDF * p)438 pdf_cleanup_document_internal(PDF *p)
439 {
440     pdf_document *doc = (pdf_document *) p->document;
441 
442     if (doc)
443     {
444         pdf_cleanup_destination(p, doc->dest);
445         doc->dest = NULL;
446 
447         if (doc->action)
448         {
449             pdc_free(p->pdc, doc->action);
450             doc->action = NULL;
451         }
452 
453         if (doc->uri)
454         {
455             pdc_free(p->pdc, doc->uri);
456             doc->uri = NULL;
457         }
458 
459         if (doc->viewerpreferences)
460         {
461             pdc_free(p->pdc, doc->viewerpreferences);
462             doc->viewerpreferences = NULL;
463         }
464 
465 
466 
467 #if defined(MVS) || defined(MVS_TEST)
468         if (doc->fopenparams)
469         {
470             pdc_free(p->pdc, doc->fopenparams);
471             doc->fopenparams = NULL;
472         }
473 
474         if (doc->tempfilenames)
475         {
476             pdc_cleanup_optstringlist(p->pdc, doc->tempfilenames, 2);
477             doc->tempfilenames = NULL;
478         }
479 #endif
480 
481 
482         if (doc->searchindexname)
483         {
484             pdc_free(p->pdc, doc->searchindexname);
485             doc->searchindexname = NULL;
486         }
487 
488         if (doc->searchindextype)
489         {
490             pdc_free(p->pdc, doc->searchindextype);
491             doc->searchindextype = NULL;
492         }
493 
494         if (doc->filename)
495         {
496             pdc_free(p->pdc, doc->filename);
497             doc->filename = NULL;
498         }
499 
500         pdc_free(p->pdc, doc);
501         p->document = NULL;
502     }
503 }
504 
505 
506 /* ---------------------------- PDFA / PDFX -------------------------- */
507 
508 
509 
510 void
pdf_fix_openmode(PDF * p)511 pdf_fix_openmode(PDF *p)
512 {
513     pdf_document *doc = pdf_init_get_document(p);
514 
515     if (doc->openmode == open_auto)
516         doc->openmode = open_bookmarks;
517 }
518 
519 
520 
521 pdc_bool
pdf_get_plainmetadata(PDF * p)522 pdf_get_plainmetadata(PDF *p)
523 {
524     (void) p;
525     return pdc_false;
526 }
527 
528 
529 /* ------------------------- viewerpreferences ----------------------- */
530 
531 static const pdc_defopt pdf_viewerpreferences_options[] =
532 {
533     {"centerwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
534       0.0, 0, NULL},
535 
536     {"direction", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
537       0.0, 0.0, pdf_textdirection_pdfkeylist},
538 
539     {"displaydoctitle", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
540       0.0, 0, NULL},
541 
542     {"fitwindow", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
543       0.0, 0, NULL},
544 
545     {"hidemenubar", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
546       0.0, 0, NULL},
547 
548     {"hidetoolbar", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
549       0.0, 0, NULL},
550 
551     {"hidewindowui", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
552       0.0, 0, NULL},
553 
554     {"nonfullscreenpagemode", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
555       0.0, 0.0, pdf_nonfullscreen_keylist},
556 
557     {"viewarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
558       0.0, 0.0, pdf_usebox_keylist},
559 
560     {"viewclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
561       0.0, 0.0, pdf_usebox_keylist},
562 
563     {"printarea", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
564       0.0, 0.0, pdf_usebox_keylist},
565 
566     {"printclip", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
567       0.0, 0.0, pdf_usebox_keylist},
568 
569     {"printscaling", pdc_keywordlist, PDC_OPT_PDC_1_6, 1, 1,
570       0.0, 0.0, pdf_printscaling_pdfkeylist},
571 
572     {"duplex", pdc_keywordlist, PDC_OPT_PDC_1_7, 1, 1,
573       0.0, 0.0, pdf_duplex_pdfkeylist},
574 
575     {"picktraybypdfsize", pdc_booleanlist, PDC_OPT_PDC_1_7, 1, 1,
576       0.0, 0, NULL},
577 
578     {"printpagerange", pdc_integerlist, PDC_OPT_PDC_1_7 | PDC_OPT_EVENNUM,
579       1, PDC_USHRT_MAX, 1.0, PDC_INT_MAX, NULL}, \
580 
581     {"numcopies", pdc_integerlist, PDC_OPT_PDC_1_7, 1, 1, \
582       1.0, 5.0, NULL}, \
583 
584     PDC_OPT_TERMINATE
585 };
586 
587 static int
pdf_parse_and_write_viewerpreferences(PDF * p,const char * optlist,pdc_bool output)588 pdf_parse_and_write_viewerpreferences(PDF *p, const char *optlist,
589                                       pdc_bool output)
590 {
591     pdc_resopt *resopts = NULL;
592     pdc_clientdata cdata;
593     char **strlist;
594     pdc_bool writevpdict = pdc_false;
595     pdc_bool flag;
596     int i, nv, inum;
597 
598     /* parsing option list */
599     pdf_set_clientdata(p, &cdata);
600     resopts = pdc_parse_optionlist(p->pdc, optlist,
601                   pdf_viewerpreferences_options, &cdata, pdc_true);
602 
603     if (pdc_get_optvalues("hidetoolbar", resopts, &flag, NULL) && flag)
604     {
605         writevpdict = pdc_true;
606         if (output) pdc_printf(p->out, "/HideToolbar true\n");
607     }
608 
609     if (pdc_get_optvalues("hidemenubar", resopts, &flag, NULL) && flag)
610     {
611         writevpdict = pdc_true;
612         if (output) pdc_printf(p->out, "/HideMenubar true\n");
613     }
614 
615     if (pdc_get_optvalues("hidewindowui", resopts, &flag, NULL) && flag)
616     {
617         writevpdict = pdc_true;
618         if (output) pdc_printf(p->out, "/HideWindowUI true\n");
619     }
620 
621     if (pdc_get_optvalues("fitwindow", resopts, &flag, NULL) && flag)
622     {
623         writevpdict = pdc_true;
624         if (output) pdc_printf(p->out, "/FitWindow true\n");
625     }
626 
627     if (pdc_get_optvalues("centerwindow", resopts, &flag, NULL) && flag)
628     {
629         writevpdict = pdc_true;
630         if (output) pdc_printf(p->out, "/CenterWindow true\n");
631     }
632 
633     if (pdc_get_optvalues("displaydoctitle", resopts, &flag, NULL) && flag)
634     {
635         writevpdict = pdc_true;
636         if (output) pdc_printf(p->out, "/DisplayDocTitle true\n");
637     }
638 
639     if (pdc_get_optvalues("nonfullscreenpagemode", resopts, &inum, NULL) &&
640         inum != (int) open_none)
641     {
642         if (inum == (int) open_layers)
643             pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0);
644         writevpdict = pdc_true;
645         if (output) pdc_printf(p->out, "/NonFullScreenPageMode/%s\n",
646                    pdc_get_keyword(inum, pdf_openmode_pdfkeylist));
647     }
648 
649 
650     if (pdc_get_optvalues("direction", resopts, &inum, NULL) &&
651         inum != (int) doc_l2r)
652     {
653         writevpdict = pdc_true;
654         if (output) pdc_printf(p->out, "/Direction/%s\n",
655                    pdc_get_keyword(inum, pdf_textdirection_pdfkeylist));
656     }
657 
658     if (pdc_get_optvalues("viewarea", resopts, &inum, NULL) &&
659         inum != (int) pdc_pbox_crop)
660     {
661         writevpdict = pdc_true;
662         if (output) pdc_printf(p->out, "/ViewArea%s\n",
663                    pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
664     }
665 
666     if (pdc_get_optvalues("viewclip", resopts, &inum, NULL) &&
667         inum != (int) pdc_pbox_crop)
668     {
669         writevpdict = pdc_true;
670         if (output) pdc_printf(p->out, "/ViewClip%s\n",
671                    pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
672     }
673 
674     if (pdc_get_optvalues("printarea", resopts, &inum, NULL) &&
675         inum != (int) pdc_pbox_crop)
676     {
677         writevpdict = pdc_true;
678         if (output) pdc_printf(p->out, "/PrintArea%s\n",
679                    pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
680     }
681 
682     if (pdc_get_optvalues("printclip", resopts, &inum, NULL) &&
683         inum != (int) pdc_pbox_crop)
684     {
685         writevpdict = pdc_true;
686         if (output) pdc_printf(p->out, "/PrintClip%s\n",
687                    pdc_get_keyword(inum, pdf_usebox_pdfkeylist));
688     }
689 
690     if (pdc_get_optvalues("printscaling", resopts, &inum, NULL) &&
691         inum != (int) doc_appdefault)
692     {
693         writevpdict = pdc_true;
694         if (output) pdc_printf(p->out, "/PrintScaling/%s\n",
695                    pdc_get_keyword(inum, pdf_printscaling_pdfkeylist));
696     }
697 
698     if (pdc_get_optvalues("duplex", resopts, &inum, NULL) &&
699         inum != (int) doc_none)
700     {
701         writevpdict = pdc_true;
702         if (output) pdc_printf(p->out, "/Duplex/%s\n",
703                    pdc_get_keyword(inum, pdf_duplex_pdfkeylist));
704     }
705 
706     if (pdc_get_optvalues("picktraybypdfsize", resopts, &flag, NULL))
707     {
708         writevpdict = pdc_true;
709         if (output) pdc_printf(p->out, "/PickTrayByPDFSize %s\n",
710                                PDC_BOOLSTR(flag));
711     }
712 
713     nv = pdc_get_optvalues("printpagerange", resopts, NULL, &strlist);
714     if (nv)
715     {
716         writevpdict = pdc_true;
717         if (output)
718         {
719             int *prs = (int *) strlist;
720 
721             pdc_printf(p->out, "/PrintPageRange");
722             pdc_begin_array(p->out);
723             for (i = 0; i < nv; i++)
724                 /* because of bug #1623: -1 */
725                 pdc_printf(p->out, "%d ", prs[i] - 1);
726             pdc_end_array(p->out);
727         }
728     }
729 
730     if (pdc_get_optvalues("numcopies", resopts, &inum, NULL))
731     {
732         writevpdict = pdc_true;
733         if (output) pdc_printf(p->out, "/NumCopies %d\n", inum);
734     }
735 
736     pdc_cleanup_optionlist(p->pdc, resopts);
737 
738     return writevpdict;
739 }
740 
741 
742 /* ------------------------- search ----------------------- */
743 
744 static const pdc_defopt pdf_search_options[] =
745 {
746     {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
747       1.0, PDC_FILENAMELEN, NULL},
748 
749     {"indextype", pdc_stringlist, PDC_OPT_NONE, 1, 1,
750       0.0, PDF_MAX_NAMESTRING, NULL},
751 
752     PDC_OPT_TERMINATE
753 };
754 
755 static void
pdf_parse_search_optlist(PDF * p,const char * optlist,pdc_encoding htenc,int htcp)756 pdf_parse_search_optlist(PDF *p, const char *optlist,
757                          pdc_encoding htenc, int htcp)
758 {
759     pdf_document *doc = p->document;
760     pdc_resopt *resopts = NULL;
761 
762     /* parsing option list */
763     resopts = pdc_parse_optionlist(p->pdc, optlist,
764                               pdf_search_options, NULL, pdc_true);
765 
766     if (pdf_get_opt_textlist(p, "filename", resopts, htenc, htcp,
767                              pdc_true, NULL, &doc->searchindexname, NULL))
768         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
769 
770     if (pdc_get_optvalues("indextype", resopts, NULL, NULL))
771         doc->searchindextype =
772             (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
773     else
774         doc->searchindextype = pdc_strdup(p->pdc, "PDX");
775 
776     pdc_cleanup_optionlist(p->pdc, resopts);
777 }
778 
779 static void
pdf_write_search_indexes(PDF * p)780 pdf_write_search_indexes(PDF *p)
781 {
782     pdf_document *doc = p->document;
783 
784     if (doc->searchindexname != NULL)
785     {
786         pdc_puts(p->out, "/Search");
787         pdc_begin_dict(p->out);                         /* Search */
788         pdc_puts(p->out, "/Indexes");
789         pdc_begin_array(p->out);
790         pdc_begin_dict(p->out);                         /* Indexes */
791         pdc_puts(p->out, "/Name");
792         pdc_printf(p->out, "/%s", doc->searchindextype);
793         pdc_puts(p->out, "/Index");
794         pdc_begin_dict(p->out);                         /* Index */
795         pdc_puts(p->out, "/Type/Filespec");
796         pdc_puts(p->out, "/F");
797         pdf_put_pdffilename(p, doc->searchindexname);
798         if (p->compatibility >= PDC_1_7)
799         {
800             pdc_printf(p->out, "/UF");
801             pdf_put_pdfunifilename(p, doc->searchindexname);
802         }
803         pdc_end_dict(p->out);                           /* Index */
804         pdc_end_dict(p->out);                           /* Indexes */
805         pdc_end_array(p->out);
806         pdc_end_dict(p->out);                           /* Search */
807     }
808 }
809 
810 
811 /* ---------------------- file attachements -------------------- */
812 
813 static void
pdc_cleanup_attachments_tmp(void * opaque,void * mem)814 pdc_cleanup_attachments_tmp(void *opaque, void *mem)
815 {
816     if (mem)
817     {
818         PDF *p = (PDF *) opaque;
819         pdf_document *doc = p->document;
820         int i;
821 
822         if (doc != NULL)
823         {
824             for (i = 0; i < doc->nattachs; i++)
825             {
826                 pdf_attachments *fat = &doc->attachments[i];
827 
828                 if (fat->filename != NULL)
829                     pdc_free(p->pdc, fat->filename);
830                 if (fat->name != NULL)
831                     pdc_free(p->pdc, fat->name);
832                 if (fat->description != NULL)
833                     pdc_free(p->pdc, fat->description);
834                 if (fat->mimetype != NULL)
835                     pdc_free(p->pdc, fat->mimetype);
836             }
837 
838             doc->attachments = NULL;
839             doc->nattachs = 0;
840         }
841     }
842 }
843 
844 static const pdc_defopt pdf_attachments_options[] =
845 {
846     {"filename", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
847       1.0, PDC_FILENAMELEN, NULL},
848 
849     {"description", pdc_stringlist, PDC_OPT_PDC_1_6, 1, 1,
850       0.0, PDC_INT_MAX, NULL},
851 
852     {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1,
853       0.0, PDF_MAX_NAMESTRING, NULL},
854 
855     {"mimetype", pdc_stringlist, PDC_OPT_NONE, 1, 1,
856       0.0, PDF_MAX_NAMESTRING, NULL},
857 
858     PDC_OPT_TERMINATE
859 };
860 
861 static void
pdf_parse_attachments_optlist(PDF * p,char ** optlists,int ns,pdc_encoding htenc,int htcp)862 pdf_parse_attachments_optlist(PDF *p, char **optlists, int ns,
863                               pdc_encoding htenc, int htcp)
864 {
865     static const char fn[] = "pdf_parse_attachments_optlist";
866     pdf_document *doc = p->document;
867     pdc_resopt *resopts = NULL;
868     pdc_clientdata cdata;
869     int i;
870 
871     doc->attachments = (pdf_attachments *) pdc_malloc_tmp(p->pdc,
872                                ns * sizeof(pdf_attachments), fn,
873                                p, pdc_cleanup_attachments_tmp);
874     doc->nattachs = ns;
875 
876     pdf_set_clientdata(p, &cdata);
877 
878     for (i = 0; i < ns; i++)
879     {
880         pdf_attachments *fat = &doc->attachments[i];
881 
882         fat->filename = NULL;
883         fat->name = NULL;
884         fat->description = NULL;
885         fat->mimetype = NULL;
886         fat->filesize = 0;
887     }
888 
889     for (i = 0; i < ns; i++)
890     {
891         pdf_attachments *fat = &doc->attachments[i];
892 
893         /* parsing option list */
894         resopts = pdc_parse_optionlist(p->pdc, optlists[i],
895                             pdf_attachments_options, &cdata, pdc_true);
896 
897         if (pdf_get_opt_textlist(p, "filename", resopts, htenc, htcp,
898                  /* bug #2344 */ pdc_undef, NULL, &fat->filename, NULL))
899             pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
900 
901         if (pdf_get_opt_textlist(p, "description", resopts, htenc, htcp,
902                                  pdc_true, NULL, &fat->description, NULL))
903             pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
904 
905         if (pdf_get_opt_textlist(p, "name", resopts, htenc, htcp,
906                                  pdc_true, NULL, &fat->name, NULL))
907             pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
908 
909         if (pdc_get_optvalues("mimetype", resopts, NULL, NULL))
910             fat->mimetype =
911                 (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
912 
913         pdc_cleanup_optionlist(p->pdc, resopts);
914 
915         fat->filesize = pdf_check_file(p, fat->filename, pdc_true);
916     }
917 }
918 
919 static void
pdf_write_attachments(PDF * p)920 pdf_write_attachments(PDF *p)
921 {
922     static const char fn[] = "pdf_write_attachments";
923     pdf_document *doc = p->document;
924     pdc_id attachment_id, obj_id;
925     const char *basename;
926     char *name;
927     int i;
928 
929     for (i = 0; i < doc->nattachs; i++)
930     {
931         pdf_attachments *fat = &doc->attachments[i];
932 
933         if (fat->filesize > 0)
934         {
935             /* create file specification dictionary */
936             attachment_id = pdc_begin_obj(p->out, PDC_NEW_ID);
937             pdc_begin_dict(p->out);                 /* FS dict */
938 
939             /* see bug #1439 */
940             basename = pdc_file_strip_dirs(fat->filename);
941 
942             pdc_puts(p->out, "/Type/Filespec\n");
943             pdc_printf(p->out, "/F");
944             pdf_put_pdffilename(p, basename);
945             pdc_puts(p->out, "\n");
946             if (p->compatibility >= PDC_1_7)
947             {
948                 pdc_printf(p->out, "/UF");
949                 pdf_put_pdfunifilename(p, basename);
950                 pdc_puts(p->out, "\n");
951             }
952 
953             if (fat->description != NULL)
954             {
955                 pdc_puts(p->out, "/Desc");
956                 pdf_put_hypertext(p, fat->description);
957                 pdc_puts(p->out, "\n");
958             }
959 
960             obj_id = pdc_alloc_id(p->out);
961             pdc_puts(p->out, "/EF");
962             pdc_begin_dict(p->out);
963             pdc_objref(p->out, "/F", obj_id);
964             pdc_end_dict(p->out);
965 
966             pdc_end_dict(p->out);                   /* FS dict */
967             pdc_end_obj(p->out);
968 
969             /* embed file */
970             pdf_embed_file(p, obj_id, fat->filename, fat->mimetype,
971                            fat->filesize);
972 
973             /* insert name in tree */
974             if (fat->name == NULL)
975                 name = pdc_strdup_ext(p->pdc, basename, 0, fn);
976             else
977                 name = pdc_strdup_ext(p->pdc, fat->name, 0, fn);
978             pdf_insert_name(p, name, names_embeddedfiles, attachment_id);
979         }
980     }
981 }
982 
983 pdc_off_t
pdf_check_file(PDF * p,const char * filename,pdc_bool verbose)984 pdf_check_file(PDF *p, const char *filename, pdc_bool verbose)
985 {
986     pdc_off_t filesize = 0;
987     const char *qualifier = "attachment ";
988     pdc_file *fp;
989 
990     fp = pdc_fsearch_fopen(p->pdc, filename, NULL, qualifier,
991                                      PDC_FILE_BINARY);
992     if (fp == NULL)
993     {
994         if (verbose)
995             pdc_error(p->pdc, -1, 0, 0, 0, 0);
996     }
997     else
998     {
999         filesize = pdc_file_size(fp);
1000         pdc_fclose(fp);
1001 
1002         if (filesize == 0)
1003         {
1004             pdc_set_errmsg(p->pdc, PDC_E_IO_FILE_EMPTY, qualifier, filename,
1005                            0, 0);
1006             if (verbose)
1007                 pdc_error(p->pdc, -1, 0, 0, 0, 0);
1008         }
1009     }
1010 
1011     return filesize;
1012 }
1013 
1014 void
pdf_embed_file(PDF * p,pdc_id obj_id,const char * filename,const char * mimetype,pdc_off_t filesize)1015 pdf_embed_file(PDF *p, pdc_id obj_id, const char *filename,
1016                const char *mimetype, pdc_off_t filesize)
1017 {
1018     pdc_id length_id;
1019     PDF_data_source src;
1020 
1021     pdc_begin_obj(p->out, obj_id);
1022     pdc_begin_dict(p->out);                    /* F dict */
1023 
1024     pdc_puts(p->out, "/Type/EmbeddedFile\n");
1025 
1026     if (mimetype && *mimetype)
1027     {
1028         pdc_puts(p->out, "/Subtype");
1029         pdf_put_pdfname(p, mimetype);
1030         pdc_puts(p->out, "\n");
1031     }
1032 
1033     pdc_puts(p->out, "/Params");
1034     pdc_begin_dict(p->out);                    /* Params */
1035     pdc_printf(p->out, "/Size %lld", filesize);
1036     pdc_end_dict(p->out);                      /* Params */
1037 
1038     if (pdc_get_compresslevel(p->out))
1039     {
1040 	pdc_puts(p->out, "/Filter/FlateDecode\n");
1041     }
1042 
1043     length_id = pdc_alloc_id(p->out);
1044     pdc_objref(p->out, "/Length", length_id);
1045 
1046     pdc_end_dict(p->out);                    /* F dict */
1047 
1048     /* write the file in the PDF */
1049     src.private_data = (void *) filename;
1050     src.init = pdf_data_source_file_init;
1051     src.fill = pdf_data_source_file_fill;
1052     src.terminate = pdf_data_source_file_terminate;
1053     src.length = (long) 0;
1054     src.offset = (long) 0;
1055 
1056 
1057     pdf_copy_stream(p, &src, pdc_true);
1058 
1059 
1060     pdc_end_obj(p->out);
1061 
1062     pdc_put_pdfstreamlength(p->out, length_id);
1063 
1064     if (p->flush & pdc_flush_content)
1065         pdc_flush_stream(p->out);
1066 }
1067 
1068 
1069 /* ---------------------- linearize -------------------- */
1070 
1071 
1072 
1073 /* ------------------ document options ----------------- */
1074 
1075 static void
pdf_get_document_common_options(PDF * p,pdc_resopt * resopts,int fcode)1076 pdf_get_document_common_options(PDF *p, pdc_resopt *resopts, int fcode)
1077 {
1078     pdf_document *doc = p->document;
1079     pdc_encoding htenc;
1080     int htcp;
1081     char **strlist;
1082     int i, inum, ns;
1083 
1084 
1085     htenc =
1086         pdf_get_hypertextencoding_opt(p, resopts, &htcp, pdc_true);
1087 
1088     if (pdc_get_optvalues("destination", resopts, NULL, &strlist))
1089     {
1090         if (doc->dest)
1091             pdc_free(p->pdc, doc->dest);
1092         doc->dest = pdf_parse_destination_optlist(p, strlist[0], 1,
1093                                                   pdf_openaction);
1094     }
1095     else
1096     {
1097         pdf_dest *dest = pdf_get_option_destname(p, resopts, htenc, htcp);
1098         if (dest)
1099         {
1100             if (doc->dest)
1101                 pdc_free(p->pdc, doc->dest);
1102             doc->dest = dest;
1103         }
1104     }
1105 
1106     if (pdc_get_optvalues("action", resopts, NULL, NULL))
1107     {
1108         if (doc->action)
1109             pdc_free(p->pdc, doc->action);
1110         doc->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1111         pdf_parse_and_write_actionlist(p, event_document, NULL, doc->action);
1112     }
1113 
1114     inum = pdc_get_optvalues("labels", resopts, NULL, &strlist);
1115     for (i = 0; i < inum; i++)
1116 	pdf_set_pagelabel(p, strlist[i], fcode);
1117 
1118     if (pdc_get_optvalues("openmode", resopts, &inum, NULL))
1119         doc->openmode = (pdf_openmode) inum;
1120 
1121         if (doc->openmode ==  open_layers)
1122             pdc_error(p->pdc, PDF_E_UNSUPP_LAYER, 0, 0, 0, 0);
1123 
1124     if (doc->openmode == open_attachments && p->compatibility < PDC_1_6)
1125         pdc_error(p->pdc, PDC_E_OPT_VERSION, "openmode=attachments",
1126                   pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
1127 
1128     if (pdc_get_optvalues("pagelayout", resopts, &inum, NULL))
1129         doc->pagelayout = (pdf_pagelayout) inum;
1130     if (p->compatibility < PDC_1_5)
1131     {
1132         if (doc->pagelayout == layout_twopageleft)
1133             pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageLeft",
1134                       pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
1135         if (doc->pagelayout == layout_twopageright)
1136             pdc_error(p->pdc, PDC_E_OPT_VERSION, "pagelayout=TwoPageRight",
1137                       pdc_get_pdfversion(p->pdc, p->compatibility), 0, 0);
1138     }
1139 
1140     if (pdc_get_optvalues("uri", resopts, NULL, NULL))
1141     {
1142         if (doc->uri)
1143             pdc_free(p->pdc, doc->uri);
1144         doc->uri = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1145     }
1146 
1147     if (pdc_get_optvalues("viewerpreferences", resopts, NULL, NULL))
1148     {
1149         if (doc->viewerpreferences)
1150             pdc_free(p->pdc, doc->viewerpreferences);
1151         doc->viewerpreferences =
1152             (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1153         doc->writevpdict |=
1154             pdf_parse_and_write_viewerpreferences(p, doc->viewerpreferences,
1155                                                   pdc_false);
1156     }
1157 
1158     if (pdc_get_optvalues("search", resopts, NULL, &strlist))
1159         pdf_parse_search_optlist(p, strlist[0], htenc, htcp);
1160 
1161 
1162     pdc_get_optvalues("moddate", resopts, &doc->moddate, NULL);
1163 
1164     ns = pdc_get_opt_utf8strings(p->pdc, "attachments", resopts, 0, &strlist);
1165     if (ns)
1166         pdf_parse_attachments_optlist(p, strlist, ns, htenc, htcp);
1167 }
1168 
1169 static const pdc_defopt pdf_begin_document_options[] =
1170 {
1171     PDF_DOCUMENT_OPTIONS1
1172 #if defined(MVS) || defined(MVS_TEST)
1173     PDF_DOCUMENT_OPTIONS10
1174 #endif
1175     PDF_DOCUMENT_OPTIONS2
1176     PDF_ERRORPOLICY_OPTION
1177     PDC_OPT_TERMINATE
1178 };
1179 
1180 
1181 /*
1182  * The external callback interface requires a PDF* as the first argument,
1183  * while the internal interface uses pdc_output* and doesn't know about PDF*.
1184  * We use a wrapper to bridge the gap, and store the PDF* within the
1185  * pdc_output structure opaquely.
1186  */
1187 
1188 static size_t
writeproc_wrapper(pdc_output * out,void * data,size_t size)1189 writeproc_wrapper(pdc_output *out, void *data, size_t size)
1190 {
1191     size_t ret;
1192 
1193     PDF *p = (PDF *) pdc_get_opaque(out);
1194 
1195     ret = (p->writeproc)(p, data, size);
1196     pdc_logg_cond(p->pdc, 1, trc_api,
1197                        "/* writeproc(data[%p], %d)[%d] */\n", data, size, ret);
1198     return ret;
1199 }
1200 
1201 
1202 
1203 /* ---------------------------- begin document -------------------------- */
1204 
1205 static int
pdf_begin_document_internal(PDF * p,const char * optlist,pdc_bool callback)1206 pdf_begin_document_internal(PDF *p, const char *optlist, pdc_bool callback)
1207 {
1208     pdf_document *doc = p->document;
1209     pdc_resopt *resopts = NULL;
1210     char **groups = NULL;
1211     int n_groups = 0;
1212     pdc_bool verbose = p->debug[(int) 'o'];
1213     pdc_outctl oc;
1214 
1215     (void) callback;
1216 
1217     verbose = pdf_get_errorpolicy(p, NULL, verbose);
1218 
1219     /* parsing option list */
1220     if (optlist && *optlist)
1221     {
1222         int inum;
1223 
1224         resopts = pdc_parse_optionlist(p->pdc, optlist,
1225                                    pdf_begin_document_options, NULL, pdc_true);
1226 
1227         verbose = pdf_get_errorpolicy(p, resopts, verbose);
1228 
1229         pdc_get_optvalues("compatibility", resopts, &doc->compatibility, NULL);
1230 
1231         if (pdc_get_optvalues("flush", resopts, &inum, NULL))
1232             doc->flush = (pdc_flush_state) inum;
1233 
1234         pdc_get_optvalues("lang", resopts, doc->lang, NULL);
1235 
1236 
1237 
1238 
1239 
1240 
1241 
1242 
1243 #if defined(MVS) || defined(MVS_TEST)
1244         if (pdc_get_optvalues("filemode", resopts, NULL, NULL))
1245         {
1246             doc->fopenparams =
1247                 (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1248         }
1249 #endif
1250 
1251 	n_groups = pdc_get_optvalues("groups", resopts, NULL, &groups);
1252     }
1253 
1254     /* copy for easy access */
1255     p->compatibility = doc->compatibility;
1256     p->pdc->compatibility = doc->compatibility;
1257     p->flush = doc->flush;
1258 
1259 
1260 
1261 
1262 
1263     /*
1264      * None of these functions must call pdc_alloc_id() or generate
1265      * any output since the output machinery is not yet initialized!
1266      */
1267 
1268     pdf_init_pages(p, (const char **) groups, n_groups);
1269 
1270     /* common options */
1271     pdf_get_document_common_options(p, resopts, PDF_FC_BEGIN_DOCUMENT);
1272 
1273 
1274     /* create document digest */
1275     pdc_init_digest(p->out);
1276 
1277     if (!p->pdc->ptfrun)
1278     {
1279 	if (doc->fp)
1280 	    pdc_update_digest(p->out, (pdc_byte *) doc->fp, doc->len);
1281 	else if (doc->writeproc)
1282 	    pdc_update_digest(p->out, (pdc_byte *) &doc->writeproc, doc->len);
1283 	else if (doc->filename)
1284 	    pdc_update_digest(p->out, (pdc_byte *) doc->filename, doc->len);
1285     }
1286 
1287     pdf_feed_digest_info(p);
1288 
1289     if (!p->pdc->ptfrun)
1290     {
1291         pdc_update_digest(p->out, (pdc_byte *) &p, sizeof(PDF*));
1292         pdc_update_digest(p->out, (pdc_byte *) p, sizeof(PDF));
1293     }
1294 
1295 
1296     pdc_finish_digest(p->out, !p->pdc->ptfrun);
1297 
1298     /* preparing output struct */
1299     pdc_init_outctl(&oc);
1300     oc.flush = doc->flush;
1301 
1302     if (doc->fp)
1303         oc.fp = doc->fp;
1304     else if (doc->writeproc)
1305     {
1306         oc.writeproc = writeproc_wrapper;
1307         p->writeproc = doc->writeproc;
1308     }
1309     else if (doc->filename)
1310         oc.filename = doc->filename;
1311     else
1312         oc.filename = "";
1313 
1314 
1315 #if defined(MVS) || defined(MVS_TEST)
1316     oc.fopenparams = doc->fopenparams;
1317 #endif
1318 
1319 
1320     PDC_TRY(p->pdc)
1321     {
1322         if (!pdc_init_output((void *) p, p->out, doc->compatibility, &oc))
1323         {
1324             if (oc.filename && *oc.filename)
1325             {
1326                 pdc_set_fopen_errmsg(p->pdc,
1327                     pdc_get_fopen_errnum(p->pdc, PDC_E_IO_WROPEN), "PDF ",
1328                     pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN,
1329                                   oc.filename));
1330                 if (verbose)
1331                 {
1332                     pdf_cleanup_document_internal(p);
1333                     PDC_RETHROW(p->pdc);
1334                 }
1335             }
1336 
1337             pdf_cleanup_document_internal(p);
1338             PDC_EXIT_TRY(p->pdc);
1339             return -1;
1340         }
1341     }
1342     PDC_CATCH(p->pdc)
1343     {
1344         pdf_cleanup_document_internal(p);
1345         if (verbose)
1346             PDC_RETHROW(p->pdc);
1347 
1348         return -1;
1349     }
1350 
1351     /* deprecated */
1352     p->bookmark_dest = pdf_init_destination(p);
1353 
1354     pdf_init_images(p);
1355     pdf_init_xobjects(p);
1356     pdf_init_fonts(p);
1357     pdf_init_outlines(p);
1358     pdf_init_annot_params(p);
1359     pdf_init_colorspaces(p);
1360     pdf_init_pattern(p);
1361     pdf_init_shadings(p);
1362     pdf_init_extgstates(p);
1363 
1364 
1365 
1366 
1367 
1368     /* Write the constant /ProcSet array once at the beginning */
1369     p->procset_id = pdc_begin_obj(p->out, PDC_NEW_ID);
1370     pdc_puts(p->out, "[/PDF/ImageB/ImageC/ImageI/Text]\n");
1371     pdc_end_obj(p->out);
1372 
1373     pdf_init_pages2(p);
1374 
1375     pdf_write_attachments(p);
1376 
1377     return 1;
1378 }
1379 
1380 #if defined(_MSC_VER) && defined(_MANAGED)
1381 #pragma unmanaged
1382 #endif
1383 int
pdf__begin_document(PDF * p,const char * filename,int len,const char * optlist)1384 pdf__begin_document(PDF *p, const char *filename, int len, const char *optlist)
1385 {
1386     pdf_document *doc;
1387     pdc_bool verbose = p->debug[(int) 'o'];
1388     int retval;
1389 
1390     verbose = pdf_get_errorpolicy(p, NULL, verbose);
1391 
1392 
1393     doc = pdf_init_get_document(p);
1394 
1395     /* file ID or filename */
1396     if (len == -1)
1397     {
1398         FILE *fp = (FILE *) filename;
1399 
1400         /*
1401          * It is the callers responsibility to open the file in binary mode,
1402          * but it doesn't hurt to make sure it really is.
1403          * The Intel version of the Metrowerks compiler doesn't have setmode().
1404          */
1405 #if !defined(__MWERKS__) && (defined(WIN32) || defined(OS2))
1406 #if !defined(__BORLANDC__) && !defined(OS2)
1407         _setmode(_fileno(fp), _O_BINARY);
1408 #else
1409         setmode(fileno(fp), O_BINARY);
1410 #endif
1411 #endif
1412 
1413         doc->fp = fp;
1414 #ifdef __DragonFly__
1415         doc->len = sizeof(struct __FILE_public);
1416 #else
1417         doc->len = sizeof(FILE);
1418 #endif
1419     }
1420     else if (filename && (*filename || len > 0))
1421     {
1422         filename = pdf_convert_filename(p, filename, len, "filename",
1423                                         PDC_CONV_WITHBOM);
1424         doc->filename = pdc_strdup(p->pdc, filename);
1425         doc->len = (int) strlen(doc->filename);
1426     }
1427 
1428     retval = pdf_begin_document_internal(p, optlist, pdc_false);
1429 
1430     if (retval > -1)
1431         PDF_SET_STATE(p, pdf_state_document);
1432 
1433     if (!p->pdc->smokerun)
1434         pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n");
1435 
1436     return retval;
1437 }
1438 #if defined(_MSC_VER) && defined(_MANAGED)
1439 #pragma managed
1440 #endif
1441 
1442 void
pdf__begin_document_callback(PDF * p,size_t (* i_writeproc)(PDF * p,void * data,size_t size),const char * optlist)1443 pdf__begin_document_callback(PDF *p,
1444     size_t (*i_writeproc)(PDF *p, void *data, size_t size), const char *optlist)
1445 {
1446     size_t (*writeproc)(PDF *, void *, size_t) = i_writeproc;
1447     pdf_document *doc;
1448 
1449     if (writeproc == NULL)
1450         pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "writeproc", 0, 0, 0);
1451 
1452     doc = pdf_init_get_document(p);
1453 
1454     /* initializing and opening the document */
1455     doc->writeproc = writeproc;
1456     doc->len = sizeof(writeproc);
1457 
1458     (void) pdf_begin_document_internal(p, optlist, pdc_true);
1459 
1460     PDF_SET_STATE(p, pdf_state_document);
1461 
1462     if (!p->pdc->smokerun)
1463         pdc_logg_cond(p->pdc, 1, trc_api, "[Begin document]\n");
1464 }
1465 
1466 /* -----------------------------  name tree  ----------------------------- */
1467 
1468 struct pdf_name_s
1469 {
1470     pdc_id              obj_id;         /* id of this name object */
1471     char *              name;           /* name string */
1472     pdf_nametree_type   type;           /* name tree type */
1473 };
1474 
1475 static void
pdf_cleanup_names(PDF * p)1476 pdf_cleanup_names(PDF *p)
1477 {
1478     int i;
1479 
1480     if (p->names == NULL)
1481         return;
1482 
1483     for (i = 0; i < p->names_number; i++)
1484     {
1485         pdc_free(p->pdc, p->names[i].name);
1486     }
1487 
1488     pdc_free(p->pdc, p->names);
1489     p->names_number = 0;
1490     p->names = NULL;
1491 }
1492 
1493 void
pdf_insert_name(PDF * p,const char * name,pdf_nametree_type type,pdc_id obj_id)1494 pdf_insert_name(PDF *p, const char *name, pdf_nametree_type type, pdc_id obj_id)
1495 {
1496     static const char fn[] = "pdf_insert_name";
1497     int i;
1498 
1499     if (p->names == NULL || p->names_number == p->names_capacity)
1500     {
1501         if (p->names == NULL)
1502         {
1503             p->names_number = 0;
1504             p->names_capacity = NAMES_CHUNKSIZE;
1505             p->names = (pdf_name *) pdc_malloc(p->pdc,
1506                 sizeof(pdf_name) * p->names_capacity, fn);
1507         }
1508         else
1509         {
1510             p->names_capacity *= 2;
1511             p->names = (pdf_name *) pdc_realloc(p->pdc, p->names,
1512                 sizeof(pdf_name) * p->names_capacity, fn);
1513         }
1514         for (i = p->names_number; i < p->names_capacity; i++)
1515         {
1516             p->names[i].obj_id = PDC_BAD_ID;
1517             p->names[i].name = NULL;
1518             p->names[i].type = names_undef;
1519         }
1520     }
1521 
1522     /* check identity */
1523     for (i = 0; i < p->names_number; i++)
1524     {
1525         if (p->names[i].type == type && !strcmp(p->names[i].name, name))
1526         {
1527             pdc_free(p->pdc, p->names[i].name);
1528             p->names[i].name = (char *) name;
1529             return;
1530         }
1531     }
1532 
1533     p->names[i].obj_id = obj_id;
1534     p->names[i].name = (char *) name;
1535     p->names[i].type = type;
1536     p->names_number++;
1537 }
1538 
1539 pdc_id
pdf_get_id_from_nametree(PDF * p,pdf_nametree_type type,const char * name)1540 pdf_get_id_from_nametree(PDF *p, pdf_nametree_type type, const char *name)
1541 {
1542     int i;
1543 
1544     for (i = 0; i < p->names_number; i++)
1545     {
1546         if (p->names[i].type == type && !strcmp(name, p->names[i].name))
1547             return p->names[i].obj_id;
1548     }
1549 
1550     return PDC_BAD_ID;
1551 }
1552 
1553 #define PDF_TREE_LEAF_SIZE 32
1554 
1555 static char *
pdf_get_numbered_name(PDF * p,pdf_nametree_type type,int ia,int * in,int nn)1556 pdf_get_numbered_name(PDF *p, pdf_nametree_type type, int ia, int *in, int nn)
1557 {
1558     int i, j = ia, n = 0;
1559 
1560     for (i = ia; i < p->names_number; i++)
1561     {
1562         if (p->names[i].type == type)
1563         {
1564             n++;
1565             if (n == nn)
1566             {
1567                 if (in != NULL)
1568                     *in = i;
1569 
1570                 return p->names[i].name;
1571             }
1572             j = i;
1573         }
1574     }
1575 
1576     return (in != NULL) ? NULL : p->names[j].name;
1577 }
1578 
1579 static pdc_id
pdf_write_names(PDF * p,pdf_nametree_type type)1580 pdf_write_names(PDF *p, pdf_nametree_type type)
1581 {
1582     static const char fn[] = "pdf_write_names";
1583     pdc_id ret = PDC_BAD_ID;
1584     int i, nnames = 0;
1585 
1586     for (i = 0; i < p->names_number; i++)
1587     {
1588         if (p->names[i].type == type)
1589         {
1590             nnames++;
1591         }
1592     }
1593 
1594     if (nnames)
1595     {
1596         char *name;
1597         int nleafs, nnodes, ik, il, ia, nn;
1598         pdc_id *idlist;
1599 
1600         nnodes = nnames / PDF_TREE_LEAF_SIZE;
1601         if (!nnodes)
1602             nleafs = nnames;
1603         else
1604             nleafs = PDF_TREE_LEAF_SIZE;
1605         if (nnames > nnodes * nleafs)
1606             nnodes++;
1607 
1608         idlist = (pdc_id *) pdc_malloc(p->pdc,
1609                                 (size_t) (nnodes * sizeof(pdc_id)), fn);
1610 
1611         for (i = 0; i < nnodes; i++)
1612             idlist[i] = pdc_alloc_id(p->out);
1613 
1614         ret = pdc_begin_obj(p->out, PDC_NEW_ID);    /* Names object */
1615         pdc_begin_dict(p->out);
1616 
1617         pdc_puts(p->out, "/Kids");
1618         pdc_begin_array(p->out);
1619         for (i = 0; i < nnodes; i++)
1620             pdc_objref_c(p->out, idlist[i]);
1621         pdc_end_array(p->out);
1622 
1623         pdc_end_dict(p->out);
1624         pdc_end_obj(p->out);                        /* Names object */
1625 
1626         ia = 0;
1627         for (ik = 0; ik < nnodes; ik++)
1628         {
1629             pdc_begin_obj(p->out, idlist[ik]);
1630             pdc_begin_dict(p->out);
1631 
1632             pdc_puts(p->out, "/Limits");
1633             pdc_begin_array(p->out);
1634 
1635             name = pdf_get_numbered_name(p, type, ia, NULL, 1);
1636             pdc_put_pdfstring(p->out, name, pdc_strlen(name));
1637 
1638             nn = (ik == nnodes - 1) ? p->names_number : nleafs;
1639             name = pdf_get_numbered_name(p, type, ia, NULL, nn);
1640             pdc_put_pdfstring(p->out, name, pdc_strlen(name));
1641 
1642             pdc_end_array(p->out);
1643 
1644             pdc_puts(p->out, "/Names");
1645             pdc_begin_array(p->out);
1646 
1647             for (il = 0; il < nn; il++)
1648             {
1649                 name = pdf_get_numbered_name(p, type, ia, &ia, 1);
1650                 if (name == NULL)
1651                     break;
1652 
1653                 pdc_put_pdfstring(p->out, name, pdc_strlen(name));
1654                 pdc_objref(p->out, "", p->names[ia].obj_id);
1655                 ia++;
1656             }
1657 
1658             pdc_end_array(p->out);
1659 
1660             pdc_end_dict(p->out);
1661             pdc_end_obj(p->out);
1662         }
1663 
1664         pdc_free(p->pdc, idlist);
1665 
1666     }
1667 
1668     return ret;
1669 }
1670 
1671 static int
name_compare(const void * a,const void * b)1672 name_compare( const void*  a, const void*  b)
1673 {
1674     pdf_name *p1 = (pdf_name *) a;
1675     pdf_name *p2 = (pdf_name *) b;
1676 
1677     return pdc_wstrcmp(p1->name, p2->name);
1678 }
1679 
1680 /* ---------------------------- write document -------------------------- */
1681 
1682 static pdc_id
pdf_write_pages_and_catalog(PDF * p,pdc_id orig_root_id)1683 pdf_write_pages_and_catalog(PDF *p, pdc_id orig_root_id)
1684 {
1685     pdf_document *doc = p->document;
1686     pdc_bool openact = pdc_false;
1687     pdc_bool forpdfa = pdc_false;
1688     pdc_id act_idlist[PDF_MAX_EVENTS];
1689     pdc_id root_id = PDC_BAD_ID;
1690     pdc_id names_dests_id = PDC_BAD_ID;
1691     pdc_id names_javascript_id = PDC_BAD_ID;
1692     pdc_id names_ap_id = PDC_BAD_ID;
1693     pdc_id names_embeddedfiles_id = PDC_BAD_ID;
1694     pdc_id outintents1_id = PDC_BAD_ID;
1695     pdc_id outintents2_id = PDC_BAD_ID;
1696 
1697     pdc_id pages_id = pdf_write_pages_tree(p);
1698     pdc_id labels_id = pdf_write_pagelabels(p);
1699 
1700 
1701 
1702     (void) orig_root_id;
1703 
1704     /* name tree dictionaries */
1705     if (p->names_number)
1706     {
1707         char *name;
1708         int i, outlen, inlen;
1709 
1710         for (i = 0; i < p->names_number; i++)
1711         {
1712             inlen = strlen(p->names[i].name);
1713             name = pdf_convert_pdfstring(p, p->names[i].name, inlen,
1714                                 PDC_CONV_WITHBOM | PDC_CONV_TRYBYTES, &outlen);
1715 
1716             if (name != p->names[i].name)
1717                 pdc_free(p->pdc, p->names[i].name);
1718 
1719             p->names[i].name = name;
1720         }
1721 
1722         qsort(p->names, (size_t) p->names_number, sizeof(pdf_name),
1723               name_compare);
1724 
1725         names_dests_id = pdf_write_names(p, names_dests);
1726         names_javascript_id = pdf_write_names(p, names_javascript);
1727         names_ap_id = pdf_write_names(p, names_ap);
1728         names_embeddedfiles_id = pdf_write_names(p, names_embeddedfiles);
1729     }
1730 
1731     (void) forpdfa;
1732 
1733 
1734 
1735 
1736     /* write action objects */
1737     if (doc->action)
1738         pdf_parse_and_write_actionlist(p, event_document, act_idlist,
1739                                        (const char *) doc->action);
1740 
1741     root_id = pdc_begin_obj(p->out, PDC_NEW_ID);	/* Catalog */
1742     pdc_begin_dict(p->out);
1743     pdc_puts(p->out, "/Type/Catalog\n");
1744 
1745     pdc_objref(p->out, "/Pages", pages_id);		/* Pages object */
1746 
1747 
1748     if (labels_id != PDC_BAD_ID)
1749     {
1750         pdc_objref(p->out, "/PageLabels", labels_id);
1751     }
1752 
1753     if (p->names_number)
1754     {
1755         pdc_printf(p->out, "/Names");
1756         pdc_begin_dict(p->out);                         /* Names */
1757 
1758         if (names_dests_id != PDC_BAD_ID)
1759             pdc_objref(p->out, "/Dests", names_dests_id);
1760         if (names_javascript_id != PDC_BAD_ID)
1761             pdc_objref(p->out, "/JavaScript", names_javascript_id);
1762         if (names_ap_id != PDC_BAD_ID)
1763             pdc_objref(p->out, "/AP", names_ap_id);
1764         if (names_embeddedfiles_id != PDC_BAD_ID)
1765             pdc_objref(p->out, "/EmbeddedFiles", names_embeddedfiles_id);
1766 
1767         pdc_end_dict(p->out);                           /* Names */
1768     }
1769 
1770     if (doc->writevpdict)
1771     {
1772         pdc_printf(p->out, "/ViewerPreferences\n");
1773         pdc_begin_dict(p->out);                         /* ViewerPreferences */
1774         pdf_parse_and_write_viewerpreferences(p,
1775                        doc->viewerpreferences, pdc_true);
1776         pdc_end_dict(p->out);                           /* ViewerPreferences */
1777     }
1778 
1779     if (doc->pagelayout != layout_default)
1780         pdc_printf(p->out, "/PageLayout/%s\n",
1781                 pdc_get_keyword(doc->pagelayout, pdf_pagelayout_pdfkeylist));
1782 
1783     if (doc->openmode != open_auto && doc->openmode != open_none)
1784         pdc_printf(p->out, "/PageMode/%s\n",
1785                 pdc_get_keyword(doc->openmode, pdf_openmode_pdfkeylist));
1786 
1787     pdf_write_outline_root(p);  /* /Outlines */
1788 
1789     if (doc->action)  /* /AA */
1790         openact = pdf_write_action_entries(p, event_document, act_idlist);
1791 
1792     if (doc->dest && !openact)
1793     {
1794         pdc_puts(p->out, "/OpenAction");
1795         pdf_write_destination(p, doc->dest);
1796     }
1797 
1798     if (doc->uri)
1799     {
1800         pdc_puts(p->out, "/URI");
1801         pdc_begin_dict(p->out);
1802         pdc_printf(p->out, "/Base");
1803         pdf_put_hypertext(p, doc->uri);
1804         pdc_end_dict(p->out);
1805     }
1806 
1807 
1808     if (doc->lang[0])
1809     {
1810         pdc_puts(p->out, "/Lang");
1811         pdf_put_hypertext(p, doc->lang);
1812         pdc_puts(p->out, "\n");
1813     }
1814 
1815     /* /StructTreeRoot /MarkInfo */
1816 
1817     /* /OCProperties */
1818 
1819     if (outintents1_id != PDC_BAD_ID || outintents2_id != PDC_BAD_ID)
1820     {
1821         pdc_puts(p->out, "/OutputIntents");
1822 	pdc_begin_array(p->out);
1823         if (outintents1_id != PDC_BAD_ID)
1824             pdc_objref(p->out, "", outintents1_id);
1825         if (outintents2_id != PDC_BAD_ID)
1826             pdc_objref(p->out, "", outintents2_id);
1827 	pdc_end_array(p->out);
1828     }
1829 
1830     /* /Search */
1831     pdf_write_search_indexes(p);
1832 
1833     /* /Metadata */
1834 
1835     /* not supported: /Threads /PieceInfo /Perms /Legal */
1836 
1837     pdc_end_dict(p->out);                               /* Catalog */
1838     pdc_end_obj(p->out);
1839 
1840     return root_id;
1841 }
1842 
1843 
1844 static void
pdf_write_document(PDF * p)1845 pdf_write_document(PDF *p)
1846 {
1847     if (PDF_GET_STATE(p) != pdf_state_error)
1848     {
1849         pdf_document *doc = p->document;
1850         pdc_id info_id = PDC_BAD_ID;
1851         pdc_id root_id = PDC_BAD_ID;
1852 
1853         if (pdf_last_page(p) == 0)
1854             pdc_error(p->pdc, PDF_E_DOC_EMPTY, 0, 0, 0, 0);
1855 
1856         pdf_write_attachments(p);
1857 
1858 
1859         /* Write all pending document information up to xref table + trailer */
1860 	info_id = pdf_write_info(p, doc->moddate);
1861 
1862         pdf_write_doc_fonts(p);                 /* font objects */
1863         pdf_write_doc_colorspaces(p);           /* color space resources */
1864         pdf_write_doc_extgstates(p);            /* ExtGState resources */
1865 	root_id = pdf_write_pages_and_catalog(p, root_id);
1866         pdf_write_outlines(p);
1867         pdc_write_xref(p->out);
1868 
1869         pdc_write_trailer(p->out, info_id, root_id, 0, -1, -1, -1);
1870     }
1871 
1872     pdc_close_output(p->out);
1873 }
1874 
1875 /* ------------------------------ end document ---------------------------- */
1876 
1877 void
pdf_cleanup_document(PDF * p)1878 pdf_cleanup_document(PDF *p)
1879 {
1880     pdf_cleanup_pages(p);
1881 
1882     if (PDF_GET_STATE(p) != pdf_state_object)
1883     {
1884         /* Don't call pdc_cleanup_output() here because we may still need
1885          * the buffer contents for pdf__get_buffer() after pdf__end_document().
1886          */
1887 
1888         pdf_delete_actions(p);
1889 
1890         pdf_cleanup_destination(p, p->bookmark_dest); /* deprecated */
1891         p->bookmark_dest = NULL;
1892         pdf_cleanup_document_internal(p);
1893         pdf_cleanup_info(p);
1894         pdf_cleanup_fonts(p);
1895         pdf_cleanup_outlines(p);
1896         pdf_cleanup_annot_params(p);
1897         pdf_cleanup_names(p);
1898         pdf_cleanup_colorspaces(p);
1899         pdf_cleanup_pattern(p);
1900         pdf_cleanup_shadings(p);
1901         pdf_cleanup_images(p);
1902         pdf_cleanup_xobjects(p);
1903         pdf_cleanup_extgstates(p);
1904 
1905 
1906 
1907 
1908 
1909 
1910 
1911 
1912 
1913         pdf_cleanup_stringlists(p);
1914 
1915         PDF_SET_STATE(p, pdf_state_object);
1916     }
1917 }
1918 
1919 static const pdc_defopt pdf_end_document_options[] =
1920 {
1921     PDF_DOCUMENT_OPTIONS2
1922     PDC_OPT_TERMINATE
1923 };
1924 
1925 void
pdf__end_document(PDF * p,const char * optlist)1926 pdf__end_document(PDF *p, const char *optlist)
1927 {
1928     pdf_document *doc;
1929 
1930     /* check if there are any suspended pages left.
1931     */
1932     pdf_check_suspended_pages(p);
1933 
1934     /* get document pointer */
1935     doc = pdf_init_get_document(p);
1936 
1937     if (optlist && *optlist)
1938     {
1939         pdc_resopt *resopts = NULL;
1940         pdc_clientdata cdata;
1941 
1942         /* parsing option list */
1943         pdf_set_clientdata(p, &cdata);
1944         resopts = pdc_parse_optionlist(p->pdc, optlist,
1945                                   pdf_end_document_options, &cdata, pdc_true);
1946 
1947         /* get options */
1948         pdf_get_document_common_options(p, resopts, PDF_FC_END_DOCUMENT);
1949 
1950     }
1951 
1952     pdf_write_document(p);
1953 
1954 
1955     pdf_cleanup_document(p);
1956 
1957     if (!p->pdc->smokerun)
1958         pdc_logg_cond(p->pdc, 1, trc_api, "[End document]\n\n");
1959 }
1960 
1961 const char *
pdf__get_buffer(PDF * p,long * size)1962 pdf__get_buffer(PDF *p, long *size)
1963 {
1964     const char *ret;
1965     pdc_off_t llsize;
1966 
1967 
1968     ret = pdc_get_stream_contents(p->out, &llsize);
1969 
1970     if (llsize > LONG_MAX)
1971 	pdc_error(p->pdc, PDF_E_DOC_GETBUF_2GB, 0, 0, 0, 0);
1972 
1973     *size = (long) llsize;
1974     return ret;
1975 }
1976 
1977 
1978 
1979 
1980 /*****************************************************************************/
1981 /**               deprecated historical document functions                  **/
1982 /*****************************************************************************/
1983 
1984 void
pdf_set_flush(PDF * p,const char * flush)1985 pdf_set_flush(PDF *p, const char *flush)
1986 {
1987     if (p->pdc->binding != NULL && strcmp(p->pdc->binding, "C++"))
1988         return;
1989 
1990     if (flush != NULL && *flush)
1991     {
1992         int i = pdc_get_keycode_ci(flush, pdf_flush_keylist);
1993         if (i != PDC_KEY_NOTFOUND)
1994         {
1995             pdf_document *doc = pdf_init_get_document(p);
1996 
1997             doc->flush = (pdc_flush_state) i;
1998             p->flush = doc->flush;
1999             return;
2000         }
2001         pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, flush, "flush",
2002                   0, 0);
2003     }
2004 }
2005 
2006 void
pdf_set_uri(PDF * p,const char * uri)2007 pdf_set_uri(PDF *p, const char *uri)
2008 {
2009     pdf_document *doc = pdf_init_get_document(p);
2010 
2011     if (doc->uri)
2012         pdc_free(p->pdc, doc->uri);
2013     doc->uri = pdc_strdup(p->pdc, uri);
2014 }
2015 
2016 
2017 void
pdf_set_compatibility(PDF * p,const char * compatibility)2018 pdf_set_compatibility(PDF *p, const char *compatibility)
2019 {
2020 
2021     if (compatibility != NULL && *compatibility)
2022     {
2023         int i = pdc_get_keycode_ci(compatibility, pdf_compatibility_keylist);
2024         if (i != PDC_KEY_NOTFOUND)
2025         {
2026             pdf_document *doc = pdf_init_get_document(p);
2027 
2028             p->compatibility = i;
2029             doc->compatibility = i;
2030             p->pdc->compatibility = i;
2031             return;
2032         }
2033         pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, compatibility, "compatibility",
2034                   0, 0);
2035     }
2036 }
2037 
2038 void
pdf_set_openaction(PDF * p,const char * openaction)2039 pdf_set_openaction(PDF *p, const char *openaction)
2040 {
2041     pdf_document *doc = pdf_init_get_document(p);
2042 
2043     if (openaction != NULL && *openaction)
2044     {
2045         pdf_cleanup_destination(p, doc->dest);
2046         doc->dest = pdf_parse_destination_optlist(p, openaction, 1,
2047                                                   pdf_openaction);
2048     }
2049 }
2050 
2051 void
pdf_set_openmode(PDF * p,const char * openmode)2052 pdf_set_openmode(PDF *p, const char *openmode)
2053 {
2054     int i;
2055 
2056     if (openmode == NULL || !*openmode)
2057         openmode = "none";
2058 
2059     i = pdc_get_keycode_ci(openmode, pdf_openmode_keylist);
2060     if (i != PDC_KEY_NOTFOUND)
2061     {
2062         pdf_document *doc = pdf_init_get_document(p);
2063 
2064         doc->openmode = (pdf_openmode) i;
2065     }
2066     else
2067         pdc_error(p->pdc, PDC_E_PAR_ILLPARAM, openmode, "openmode", 0, 0);
2068 }
2069 
2070 void
pdf_set_viewerpreference(PDF * p,const char * viewerpreference)2071 pdf_set_viewerpreference(PDF *p, const char *viewerpreference)
2072 {
2073     static const char fn[] = "pdf_set_viewerpreference";
2074     pdf_document *doc = pdf_init_get_document(p);
2075     char *optlist;
2076     size_t nb1 = 0, nb2 = 0;
2077 
2078     if (doc->viewerpreferences)
2079         nb1 = strlen(doc->viewerpreferences) * sizeof(char *);
2080     nb2 = strlen(viewerpreference) * sizeof(char *);
2081 
2082     optlist = (char *) pdc_malloc(p->pdc, nb1 + nb2 + 2, fn);
2083     optlist[0] = 0;
2084     if (doc->viewerpreferences)
2085     {
2086         strcat(optlist, doc->viewerpreferences);
2087         strcat(optlist, " ");
2088     }
2089     strcat(optlist, viewerpreference);
2090 
2091     if (doc->viewerpreferences)
2092         pdc_free(p->pdc, doc->viewerpreferences);
2093     doc->viewerpreferences = optlist;
2094     doc->writevpdict |=
2095         pdf_parse_and_write_viewerpreferences(p, optlist, pdc_false);
2096 }
2097 
2098 
2099 
2100 
2101 
2102 
2103 
2104 
2105