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