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_annots.c,v 1.198.2.30 2010/04/16 12:32:27 kurt Exp $
14  *
15  * PDFlib routines for annnotations
16  *
17  */
18 
19 #define P_ANNOTS_C
20 
21 #include "p_intern.h"
22 #include "p_color.h"
23 #include "p_font.h"
24 #include "p_image.h"
25 
26 
27 
28 
29 /* annotation types */
30 typedef enum
31 {
32     ann_text            = (1<<0),
33     ann_link            = (1<<1),
34     ann_freetext        = (1<<2),
35     ann_line            = (1<<3),
36     ann_square          = (1<<4),
37     ann_circle          = (1<<5),
38     ann_highlight       = (1<<6),
39     ann_underline       = (1<<7),
40     ann_squiggly        = (1<<8),
41     ann_strikeout       = (1<<9),
42     ann_stamp           = (1<<10),
43     ann_ink             = (1<<11),
44     ann_polygon         = (1<<12),
45     ann_polyline        = (1<<13),
46     ann_popup           = (1<<14),
47     ann_fileattachment  = (1<<15),
48     ann_3d              = (1<<16),
49     ann_movie           = (1<<17)
50 }
51 pdf_annottype;
52 
53 static const pdc_keyconn pdf_annottype_pdfkeylist[] =
54 {
55     {"Text",            ann_text},
56     {"Link",            ann_link},
57     {"FreeText",        ann_freetext},
58     {"Line",            ann_line},
59     {"Square",          ann_square},
60     {"Circle",          ann_circle},
61     {"Highlight",       ann_highlight},
62     {"Underline",       ann_underline},
63     {"Squiggly",        ann_squiggly},
64     {"StrikeOut",       ann_strikeout},
65     {"Stamp",           ann_stamp},
66     {"Polygon",         ann_polygon},
67     {"PolyLine",        ann_polyline},
68     {"Ink",             ann_ink},
69     {"Popup",           ann_popup},
70     {"FileAttachment",  ann_fileattachment},
71     {"3D",              ann_3d},
72     {"Movie",           ann_movie},
73     {NULL, 0}
74 };
75 
76 static const pdc_keyconn pdf_polyline_pdfkeylist[] =
77 {
78     {"QuadPoints",  ann_link},
79     {"QuadPoints",  ann_highlight},
80     {"QuadPoints",  ann_underline},
81     {"QuadPoints",  ann_squiggly},
82     {"QuadPoints",  ann_strikeout},
83     {"InkList",     ann_ink},
84     {"Vertices",    ann_polygon},
85     {"Vertices",    ann_polyline},
86     {NULL, 0}
87 };
88 
89 /* flags for annotation dictionary entries */
90 typedef enum
91 {
92     anndict_a          = (1<<0),
93     anndict_bs         = (1<<1),
94     anndict_c          = (1<<2),
95     anndict_contents   = (1<<3),
96     anndict_f          = (1<<4),
97     anndict_fs         = (1<<5),
98     anndict_h          = (1<<6),
99     anndict_ic         = (1<<7),
100     anndict_inklist    = (1<<8),
101     anndict_l          = (1<<9),
102     anndict_le         = (1<<10),
103     anndict_movie      = (1<<11),
104     anndict_name       = (1<<12),
105     anndict_nm         = (1<<13),
106     anndict_open       = (1<<14),
107     anndict_parent     = (1<<15),
108     anndict_popup      = (1<<16),
109     anndict_q          = (1<<17),
110     anndict_quadpoints = (1<<18),
111     anndict_rect       = (1<<19),
112     anndict_subtype    = (1<<20),
113     anndict_t          = (1<<21),
114     anndict_vertices   = (1<<22),
115     anndict_3dd        = (1<<23),
116     anndict_3da        = (1<<24),
117     anndict_3dv        = (1<<25)
118 }
119 pdf_anndictentries;
120 
121 static const pdc_keyconn pdf_perm_entries_pdfkeylist[] =
122 {
123     {"Contents",   anndict_contents},
124     {"Name",       anndict_name},
125     {"NM",         anndict_nm},
126     {"Open",       anndict_open},
127     {NULL, 0}
128 };
129 
130 static const pdc_keyconn pdf_forb_entries_pdfkeylist[] =
131 {
132     {"A",          anndict_a},
133     {"BS",         anndict_bs},
134     {"C",          anndict_c},
135     {"F",          anndict_f},
136     {"FS",         anndict_fs},
137     {"H",          anndict_h},
138     {"IC",         anndict_ic},
139     {"InkList",    anndict_inklist},
140     {"L",          anndict_l},
141     {"LE",         anndict_le},
142     {"Movie",      anndict_movie},
143     {"Parent",     anndict_parent},
144     {"Popup",      anndict_popup},
145     {"Q",          anndict_q},
146     {"QuadPoints", anndict_quadpoints},
147     {"Rect",       anndict_rect},
148     {"Subtype",    anndict_subtype},
149     {"T",          anndict_t},
150     {"Vertices",   anndict_vertices},
151     {"3DD",        anndict_3dd},
152     {"3DV",        anndict_3dv},
153     {"3DA",        anndict_3da},
154     {NULL, 0}
155 };
156 
157 /* line ending styles */
158 typedef enum
159 {
160     line_none,
161     line_square,
162     line_circle,
163     line_diamond,
164     line_openarrow,
165     line_closedarrow
166 }
167 pdf_endingstyles;
168 
169 static const pdc_keyconn pdf_endingstyles_pdfkeylist[] =
170 {
171     {"None",            line_none},
172     {"Square",          line_square},
173     {"Circle",          line_circle},
174     {"Diamond",         line_diamond},
175     {"OpenArrow",       line_openarrow},
176     {"ClosedArrow",     line_closedarrow},
177     {NULL, 0}
178 };
179 
180 /* text icon names */
181 typedef enum
182 {
183     icon_text_comment,
184     icon_text_help,
185     icon_text_key,
186     icon_text_insert,
187     icon_text_newparagraph,
188     icon_text_note,
189     icon_text_paragraph
190 }
191 pdf_text_iconnames;
192 
193 static const pdc_keyconn pdf_text_iconnames_pdfkeylist[] =
194 {
195     {"Comment",         icon_text_comment},
196     {"Help",            icon_text_help},
197     {"Key",             icon_text_key},
198     {"Insert",          icon_text_insert},
199     {"NewParagraph",    icon_text_newparagraph},
200     {"Note",            icon_text_note},
201     {"Paragraph",       icon_text_paragraph},
202     {NULL, 0}
203 };
204 
205 /* stamp icon names */
206 typedef enum
207 {
208     icon_stamp_approved,
209     icon_stamp_asls,
210     icon_stamp_confidential,
211     icon_stamp_departmental,
212     icon_stamp_draft,
213     icon_stamp_experimental,
214     icon_stamp_expired,
215     icon_stamp_final,
216     icon_stamp_forcomment,
217     icon_stamp_forpublicrelease,
218     icon_stamp_notapproved,
219     icon_stamp_notforpublicrelease,
220     icon_stamp_sold,
221     icon_stamp_topsecret
222 }
223 pdf_stamp_iconnames;
224 
225 static const pdc_keyconn pdf_stamp_iconnames_pdfkeylist[] =
226 {
227     {"Approved",               icon_stamp_approved},
228     {"AsIs",                   icon_stamp_asls},
229     {"Confidential",           icon_stamp_confidential},
230     {"Departmental",           icon_stamp_departmental},
231     {"Draft",                  icon_stamp_draft},
232     {"Experimental",           icon_stamp_experimental},
233     {"Expired",                icon_stamp_expired},
234     {"Final",                  icon_stamp_final},
235     {"ForComment",             icon_stamp_forcomment},
236     {"ForPublicRelease",       icon_stamp_forpublicrelease},
237     {"NotApproved",            icon_stamp_notapproved},
238     {"NotForPublicRelease",    icon_stamp_notforpublicrelease},
239     {"Sold",                   icon_stamp_sold},
240     {"TopSecret",              icon_stamp_topsecret},
241     {NULL, 0}
242 };
243 
244 /* file attachment icon names */
245 typedef enum
246 {
247     icon_attach_graph,
248     icon_attach_paperclip,
249     icon_attach_pushpin,
250     icon_attach_tag
251 }
252 pdf_attach_iconnames;
253 
254 static const pdc_keyconn pdf_attach_iconnames_pdfkeylist[] =
255 {
256     {"Graph",           icon_attach_graph},
257     {"Paperclip",       icon_attach_paperclip},
258     {"PushPin",         icon_attach_pushpin},
259     {"Tag",             icon_attach_tag},
260     {NULL, 0}
261 };
262 
263 
264 static const pdc_keyconn pdf_3dview_keylist[] =
265 {
266     {NULL, 0}
267 };
268 
269 
270 typedef enum
271 {
272     movieposter_none = -1,
273     movieposter_auto = -2
274 }
275 pdf_movieposter_states;
276 
277 static const pdc_keyconn pdf_movieposter_keylist[] =
278 {
279     {"none",     movieposter_none},
280     {"auto",     movieposter_auto},
281     {NULL, 0}
282 };
283 
284 typedef enum
285 {
286     playmode_once,
287     playmode_open,
288     playmode_repeat,
289     playmode_palindrome
290 }
291 pdf_playmode_states;
292 
293 static const pdc_keyconn pdf_playmode_pdfkeylist[] =
294 {
295     {"Once",       playmode_once},
296     {"Open",       playmode_open},
297     {"Repeat",     playmode_repeat},
298     {"Palindrome", playmode_palindrome},
299     {NULL, 0}
300 };
301 
302 #define PDF_ANN_FULLSCREEN -9999
303 
304 static const pdc_keyconn pdf_windowscale_keylist[] =
305 {
306     {"fullscreen",  PDF_ANN_FULLSCREEN},
307     {NULL, 0}
308 };
309 
310 
311 #define PDF_LAYER_FLAG PDC_OPT_UNSUPP
312 
313 #define PDF_3DANNOT_FLAG PDC_OPT_UNSUPP
314 static const pdc_defopt pdf_create_annot_options[] =
315 {
316     /* deprecated */
317     {"annotwarning", pdc_booleanlist, PDC_OPT_PDFLIB_7, 1, 1,
318       0.0, 0.0, NULL},
319 
320     {"usercoordinates", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
321       0.0, 0.0, NULL},
322 
323     {"hypertextencoding", pdc_stringlist,  PDC_OPT_NONE, 1, 1,
324       0.0, PDF_MAX_NAMESTRING, NULL},
325 
326     {"custom", pdc_stringlist, PDC_OPT_NONE, 1, 64,
327       0.0, PDC_INT_MAX, NULL},
328 
329     {"name", pdc_stringlist, PDC_OPT_NONE, 1, 1,
330       0.0, PDC_USHRT_MAX, NULL},
331 
332     {"parentname", pdc_stringlist, PDC_OPT_NONE, 1, 1,
333       0.0, PDC_USHRT_MAX, NULL},
334 
335     {"popup", pdc_stringlist, PDC_OPT_NONE, 1, 1,
336       0.0, PDC_USHRT_MAX, NULL},
337 
338     {"title", pdc_stringlist, PDC_OPT_NONE, 1, 1,
339       0.0, PDC_USHRT_MAX, NULL},
340 
341     {"subject", pdc_stringlist, PDC_OPT_PDC_1_5, 1, 1,
342       0.0, PDC_USHRT_MAX, NULL},
343 
344     {"annotcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5,
345       0.0, PDF_MAX_NAMESTRING, NULL},
346 
347     {"borderstyle", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
348       0.0, 0.0, pdf_borderstyle_keylist},
349 
350     {"dasharray", pdc_scalarlist, PDC_OPT_NONE, 1, 2,
351       PDC_FLOAT_PREC, PDC_FLOAT_MAX, NULL},
352 
353     {"linewidth", pdc_integerlist, PDC_OPT_NONE, 1, 1,
354       0.0, PDC_USHRT_MAX, NULL},
355 
356     {"opacity", pdc_scalarlist, PDC_OPT_PDC_1_4 | PDC_OPT_PERCENT, 1, 1,
357      0.0, 1.0, NULL},
358 
359     {"highlight", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
360       0.0, 0.0, pdf_highlight_keylist},
361 
362     {"display", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
363       0.0, 0.0, pdf_display_keylist},
364 
365     {"zoom", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
366       0.0, 0.0, NULL},
367 
368     {"rotate", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
369       0.0, 0.0, NULL},
370 
371     {"readonly", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
372       0.0, 0.0, NULL},
373 
374     {"locked", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1,
375       0.0, 0.0, NULL},
376 
377     {"open", pdc_booleanlist, PDC_OPT_PDC_1_4, 1, 1,
378       0.0, 0.0, NULL},
379 
380     {"createdate", pdc_booleanlist, PDC_OPT_PDC_1_5, 1, 1,
381       0.0, 0.0, NULL},
382 
383     {"fillcolor", pdc_stringlist, PDC_OPT_NONE, 2, 5,
384       0.0, PDF_MAX_NAMESTRING, NULL},
385 
386     {"alignment", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
387       0.0, 0.0, pdf_quadding_keylist},
388 
389     {"font", pdc_fonthandle, PDC_OPT_NONE, 1, 1,
390       0.0, 0.0, NULL},
391 
392     {"fontsize", pdc_scalarlist, PDC_OPT_SUBOPTLIST | PDC_OPT_KEYLIST1, 1, 2,
393       0.0, PDC_FLOAT_MAX, pdf_fontsize_keylist},
394 
395     {"orientate", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
396       0.0, 0.0, pdf_orientate_keylist},
397 
398     {"contents", pdc_stringlist, PDC_OPT_NONE, 1, 1,
399       0.0, PDC_INT_MAX, NULL},
400 
401     {"destination", pdc_stringlist, PDC_OPT_NONE, 1, 1,
402       0.0, PDC_USHRT_MAX, NULL},
403 
404     {"destname", pdc_stringlist, PDC_OPT_IGNOREIF1, 1, 1,
405       0.0, PDC_USHRT_MAX, NULL},
406 
407     {"filename", pdc_stringlist, PDC_OPT_NONE, 1, 1,
408       1.0, PDC_FILENAMELEN, NULL},
409 
410     {"mimetype", pdc_stringlist, PDC_OPT_NONE, 1, 1,
411       0.0, PDF_MAX_NAMESTRING, NULL},
412 
413     {"iconname", pdc_stringlist, PDC_OPT_NONE, 1, 1,
414       0.0, PDF_MAX_NAMESTRING, NULL},
415 
416     {"endingstyles", pdc_keywordlist, PDC_OPT_NONE, 2, 2,
417       0.0, 0.0, pdf_endingstyles_pdfkeylist},
418 
419     {"interiorcolor", pdc_stringlist, PDC_OPT_NONE, 1, 5,
420       0.0, PDF_MAX_NAMESTRING, NULL},
421 
422     {"cloudy", pdc_scalarlist, PDC_OPT_PDC_1_5, 1, 1,
423       0.0, 2.0, NULL},
424 
425     {"line", pdc_scalarlist, PDC_OPT_NONE, 4, 4,
426       PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
427 
428     {"polylinelist", pdc_polylinelist, PDC_OPT_NONE, 1, PDF_MAXARRAYSIZE,
429       PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
430 
431     {"action", pdc_stringlist, PDC_OPT_NONE, 1, 1,
432       0.0, PDC_USHRT_MAX, NULL},
433 
434     {"usematchbox", pdc_stringlist, PDC_OPT_NONE, 1, 1,
435       0.0, PDC_USHRT_MAX, NULL},
436 
437     {"layer", pdc_layerhandle, PDF_LAYER_FLAG, 1, 1,
438       0.0, 0.0, NULL},
439 
440     {"3dactivate", pdc_stringlist, PDF_3DANNOT_FLAG, 1, 1,
441       0.0, PDC_USHRT_MAX, NULL},
442 
443     {"3dbox", pdc_scalarlist, PDF_3DANNOT_FLAG, 4, 4,
444       PDC_FLOAT_MIN, PDC_FLOAT_MAX, NULL},
445 
446     {"3ddata", pdc_3ddatahandle, PDF_3DANNOT_FLAG, 1, 1,
447       0.0, 0.0, NULL},
448 
449     {"3dinteractive", pdc_booleanlist, PDF_3DANNOT_FLAG, 1, 1,
450       0.0, 0.0, NULL},
451 
452     {"3dshared", pdc_booleanlist, PDF_3DANNOT_FLAG, 1, 1,
453       0.0, 0.0, NULL},
454 
455     {"3dinitialview", pdc_3dviewhandle, PDF_3DANNOT_FLAG, 1, 1,
456       0.0, 0.0, pdf_3dview_keylist},
457 
458     {"movieposter", pdc_templatehandle, PDC_OPT_NONE, 1, 1,
459       0.0, 0.0, pdf_movieposter_keylist},
460 
461     {"showcontrols", pdc_booleanlist, PDC_OPT_NONE, 1, 1,
462       0.0, 0.0, NULL},
463 
464     {"playmode", pdc_keywordlist, PDC_OPT_NONE, 1, 1,
465       0.0, 0.0, pdf_playmode_pdfkeylist},
466 
467     {"windowscale", pdc_scalarlist, PDC_OPT_NONE, 1, 1,
468       PDC_FLOAT_PREC, PDC_FLOAT_MAX, pdf_windowscale_keylist},
469 
470     {"windowposition", pdc_scalarlist, PDC_OPT_NONE, 1, 2,
471       0.0, 100.0, pdf_position_keylist},
472 
473     {"soundvolume", pdc_scalarlist, PDC_OPT_NONE, 1, 1,
474       -1.0, 1.0, NULL},
475 
476     PDC_OPT_TERMINATE
477 };
478 
479 /* Annotation member */
480 typedef struct pdf_annot_s
481 {
482     pdc_bool iscopy;
483     pdc_id obj_id;
484     pdf_annottype atype;
485     int mask;
486     pdc_rectangle rect;
487     pdc_bool usercoordinates;
488     pdc_encoding hypertextencoding;
489     int hypertextcodepage;
490     pdf_coloropt annotcolor;
491     pdf_coloropt interiorcolor;
492     pdf_coloropt fillcolor;
493     int linewidth;
494     pdc_scalar opacity;
495     pdf_borderstyle borderstyle;
496     pdc_scalar dasharray[2];
497     pdf_highlight highlight;
498     pdf_display display;
499     pdc_bool zoom;
500     pdc_bool rotate;
501     pdc_bool kreadonly;
502     pdc_bool locked;
503     pdc_bool open;
504     pdc_bool createdate;
505     int font;
506     pdc_scalar fontsize;
507     int orientate;
508     pdf_quadding alignment;
509     pdf_endingstyles endingstyles[2];
510     pdc_scalar cloudy;
511     pdf_dest *dest;
512     char *name;
513     char *parentname;
514     char *popup;
515     char *title;
516     char *subject;
517     char *contents;
518     char *filename;
519     char *nativefilename;
520     char *mimetype;
521     const char *iconname;
522     pdc_off_t filesize;
523     pdc_scalar *line;
524     pdc_polyline *polylinelist;
525     int nplines;
526     char **custom;
527     int ncustoms;
528     char *action;
529 
530 
531 
532     pdc_id movieposter;
533     pdc_bool showcontrols;
534     pdf_playmode_states playmode;
535     pdc_scalar windowscale;
536     pdc_scalar windowposition[2];
537     pdc_scalar soundvolume;
538 }
539 pdf_annot;
540 
541 static void
pdf_reclaim_annot(void * item)542 pdf_reclaim_annot(void *item)
543 {
544     pdf_annot *ann = (pdf_annot *) item;
545 
546     ann->iscopy = pdc_false;
547     ann->obj_id = PDC_BAD_ID;
548     ann->atype = (pdf_annottype)0;
549     ann->mask = 0;
550     ann->usercoordinates = pdc_false;
551     ann->hypertextencoding = pdc_invalidenc;
552     ann->hypertextcodepage = 0;
553     ann->annotcolor.type = (int) color_none;
554     ann->interiorcolor.type = (int) color_none;
555     ann->fillcolor.type = (int) color_none;
556     ann->linewidth = 1;
557     ann->opacity = 1;
558     ann->borderstyle = border_solid;
559     ann->dasharray[0] = 3;
560     ann->dasharray[1] = 3;
561     ann->highlight = high_invert;
562     ann->display = disp_visible;
563     ann->zoom = pdc_true;
564     ann->rotate = pdc_true;
565     ann->kreadonly = pdc_false;
566     ann->locked = pdc_false;
567     ann->open = pdc_false;
568     ann->createdate = pdc_false;
569     ann->font = -1;
570     ann->fontsize = 0;
571     ann->orientate = 0;
572     ann->alignment = quadd_left;
573     ann->cloudy = -1;
574     ann->endingstyles[0] = line_none;
575     ann->endingstyles[1] = line_none;
576     ann->dest = NULL;
577     ann->name = NULL;
578     ann->parentname = NULL;
579     ann->popup = NULL;
580     ann->title = NULL;
581     ann->subject = NULL;
582     ann->contents = NULL;
583     ann->filename = NULL;
584     ann->nativefilename = NULL;
585     ann->mimetype = NULL;
586     ann->iconname = NULL;
587     ann->filesize = 0;
588     ann->line = NULL;
589     ann->polylinelist = NULL;
590     ann->nplines = 0;
591     ann->custom = NULL;
592     ann->ncustoms = 0;
593     ann->action = NULL;
594 
595 
596 
597 
598 
599     ann->movieposter = PDC_BAD_ID /* = movieposter_none */;
600     ann->showcontrols = pdc_false;
601     ann->playmode = playmode_once;
602     ann->windowscale = 0;
603     ann->windowposition[0] = 50.0;
604     ann->windowposition[1] = 50.0;
605     ann->soundvolume = 1.0;
606 }
607 
608 static void
pdf_release_annot(void * context,void * item)609 pdf_release_annot(void *context, void *item)
610 {
611     PDF *p = (PDF *) context;
612     pdf_annot *ann = (pdf_annot *) item;
613 
614     /* is not a copy */
615     if (!ann->iscopy)
616     {
617         pdf_cleanup_destination(p, ann->dest);
618         ann->dest = NULL;
619 
620         if (ann->name)
621         {
622             pdc_free(p->pdc, ann->name);
623             ann->name = NULL;
624         }
625         if (ann->parentname)
626         {
627             pdc_free(p->pdc, ann->parentname);
628             ann->parentname = NULL;
629         }
630         if (ann->popup)
631         {
632             pdc_free(p->pdc, ann->popup);
633             ann->popup = NULL;
634         }
635         if (ann->title)
636         {
637             pdc_free(p->pdc, ann->title);
638             ann->title = NULL;
639         }
640         if (ann->subject)
641         {
642             pdc_free(p->pdc, ann->subject);
643             ann->subject = NULL;
644         }
645         if (ann->contents)
646         {
647             pdc_free(p->pdc, ann->contents);
648             ann->contents = NULL;
649         }
650         if (ann->filename)
651         {
652             pdc_free(p->pdc, ann->filename);
653             ann->filename = NULL;
654         }
655         if (ann->nativefilename)
656         {
657             pdc_free(p->pdc, ann->nativefilename);
658             ann->nativefilename = NULL;
659         }
660         if (ann->mimetype)
661         {
662             pdc_free(p->pdc, ann->mimetype);
663             ann->mimetype = NULL;
664         }
665         if (ann->line)
666         {
667             pdc_free(p->pdc, ann->line);
668             ann->line = NULL;
669         }
670         if (ann->custom)
671         {
672             pdc_cleanup_optstringlist(p->pdc, ann->custom, ann->ncustoms);
673             ann->custom = NULL;
674             ann->ncustoms = 0;
675         }
676         if (ann->action)
677         {
678             pdc_free(p->pdc, ann->action);
679             ann->action = NULL;
680         }
681     }
682 
683     ann->polylinelist = (pdc_polyline *)pdc_delete_polylinelist(
684 			    p->pdc, ann->polylinelist, ann->nplines);
685 }
686 
687 static pdc_ced pdf_annot_ced =
688 {
689     sizeof(pdf_annot), pdf_reclaim_annot, pdf_release_annot, NULL
690 };
691 
692 static pdc_vtr_parms pdf_annot_parms =
693 {
694     0, 10, 10
695 };
696 
697 static pdf_annot *
pdf_new_annot(PDF * p,pdf_annottype atype)698 pdf_new_annot(PDF *p, pdf_annottype atype)
699 {
700     pdc_vtr *annots = pdf_get_annots_list(p);
701     pdf_annot *ann;
702 
703     if (annots == NULL)
704     {
705         annots = pdc_vtr_new(p->pdc, &pdf_annot_ced, p, &pdf_annot_parms);
706         pdf_set_annots_list(p, annots);
707     }
708 
709     ann = pdc_vtr_incr(annots, pdf_annot);
710     ann->atype = atype;
711 
712 
713     ann->usercoordinates = p->usercoordinates;
714     ann->hypertextencoding = p->hypertextencoding;
715     ann->hypertextcodepage = p->hypertextcodepage;
716     pdf_init_coloropt(p, &ann->fillcolor);
717 
718     return ann;
719 }
720 
721 static void
pdf_delete_last_annot(PDF * p)722 pdf_delete_last_annot(PDF *p)
723 {
724     pdc_vtr *annots = pdf_get_annots_list(p);
725 
726     if (annots != NULL)
727     {
728         if (pdc_vtr_size(annots) > 1)
729         {
730             pdc_vtr_pop(annots);
731         }
732         else
733         {
734             pdc_vtr_delete(annots);
735             pdf_set_annots_list(p, NULL);
736         }
737     }
738 }
739 
740 static void
pdf_init_rectangle(PDF * p,pdf_annot * ann,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,pdc_vector * polyline)741 pdf_init_rectangle(PDF *p, pdf_annot *ann,
742          pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury,
743          pdc_vector *polyline)
744 {
745     static const char fn[] = "pdf_init_rectangle";
746     pdc_matrix *ctm = &p->curr_ppt->gstate[p->curr_ppt->sl].ctm;
747     int i;
748 
749     pdc_check_number(p->pdc, "llx", llx);
750     pdc_check_number(p->pdc, "lly", lly);
751     pdc_check_number(p->pdc, "urx", urx);
752     pdc_check_number(p->pdc, "ury", ury);
753 
754     pdc_delete_polylinelist(p->pdc, ann->polylinelist, ann->nplines);
755     ann->nplines = 1;
756     ann->polylinelist = (pdc_polyline *) pdc_malloc(p->pdc,
757                                ann->nplines * sizeof(pdc_polyline), fn);
758     ann->polylinelist[0].np = 5;
759     ann->polylinelist[0].p = (pdc_vector *) pdc_malloc(p->pdc,
760                       ann->polylinelist[0].np * sizeof(pdc_vector), fn);
761 
762     if (polyline == NULL)
763     {
764         if (!ann->usercoordinates)
765             ctm = NULL;
766         pdc_rect_init(&ann->rect, llx, lly, urx, ury);
767         pdc_rect2polyline(ctm, &ann->rect, ann->polylinelist[0].p);
768     }
769     else
770     {
771         for (i = 0; i < 5; i++)
772             pdc_transform_vector(ctm, &polyline[i],
773                                  &ann->polylinelist[0].p[i]);
774     }
775 
776     if (ctm != NULL)
777         pdc_polyline2rect(ann->polylinelist[0].p, 4, &ann->rect);
778 }
779 
780 /* because of Acrobat muddle */
781 static void
pdf_permute_coordinates(pdf_annot * ann,pdf_annottype atype)782 pdf_permute_coordinates(pdf_annot *ann, pdf_annottype atype)
783 {
784     if (ann->nplines == 1 &&
785          (atype == ann_highlight ||
786           atype == ann_underline ||
787           atype == ann_squiggly ||
788           atype == ann_strikeout))
789     {
790         pdc_vector pl[5];
791         int i;
792 
793         for (i = 0; i < ann->polylinelist[0].np; i++)
794             pl[i] = ann->polylinelist[0].p[i];
795 
796         ann->polylinelist[0].p[0] = pl[3];
797         ann->polylinelist[0].p[1] = pl[2];
798         ann->polylinelist[0].p[2] = pl[0];
799         ann->polylinelist[0].p[3] = pl[1];
800         ann->polylinelist[0].p[4] = pl[3];
801     }
802 }
803 
804 static const pdc_keyconn pdf_keytype_keylist[] =
805 {
806     {"boolean", pdc_booleanlist},
807     {"name",    pdc_keywordlist},
808     {"string",  pdc_stringlist},
809     {NULL, 0}
810 };
811 
812 static const pdc_defopt pdf_custom_list_options[] =
813 {
814     {"key", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
815       1.0, PDF_MAX_NAMESTRING, NULL},
816 
817     {"type", pdc_keywordlist, PDC_OPT_REQUIRED, 1, 1,
818       0.0, 0.0, pdf_keytype_keylist},
819 
820     {"value", pdc_stringlist, PDC_OPT_REQUIRED, 1, 1,
821       1.0, PDC_USHRT_MAX, NULL},
822 
823     PDC_OPT_TERMINATE
824 };
825 
826 static void
pdf_parse_and_write_annot_customlist(PDF * p,pdf_annot * ann,pdc_bool output)827 pdf_parse_and_write_annot_customlist(PDF *p, pdf_annot *ann, pdc_bool output)
828 {
829     int i;
830 
831     /* custom entries */
832     for (i = 0; i < ann->ncustoms; i++)
833     {
834         pdc_resopt *resopts = NULL;
835         const char *stemp;
836         const char *keyword;
837         char **strlist = NULL;
838         char *string;
839         int inum;
840 
841         resopts = pdc_parse_optionlist(p->pdc, ann->custom[i],
842                                pdf_custom_list_options, NULL, pdc_true);
843 
844         keyword = "key";
845         pdc_get_optvalues(keyword, resopts, NULL, &strlist);
846         string = strlist[0];
847 
848         inum = pdc_get_keycode(string, pdf_forb_entries_pdfkeylist);
849         if (inum != PDC_KEY_NOTFOUND)
850         {
851             stemp = pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, string);
852             pdc_error(p->pdc, PDF_E_ANN_ILLCUSTOMKEY, stemp, 0, 0, 0);
853         }
854         inum = pdc_get_keycode(string, pdf_perm_entries_pdfkeylist);
855         if (inum != PDC_KEY_NOTFOUND)
856             ann->mask |= inum;
857 
858         if (output)
859             pdc_printf(p->out, "/%s", string);
860 
861         keyword = "type";
862         pdc_get_optvalues(keyword, resopts, &inum, NULL);
863 
864         keyword = "value";
865         pdc_get_optvalues(keyword, resopts, NULL, &strlist);
866         string = strlist[0];
867 
868         switch (inum)
869         {
870             case pdc_booleanlist:
871             if (pdc_stricmp(string, "true") && pdc_stricmp(string, "false"))
872             {
873                 stemp =
874 		    pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, string);
875 
876                 pdc_error(p->pdc, PDC_E_OPT_ILLBOOLEAN, keyword, stemp, 0, 0);
877             }
878             if (output)
879                 pdc_printf(p->out, " %s",
880                            PDC_BOOLSTR(pdc_stricmp(string, "false")));
881             break;
882 
883             case pdc_keywordlist:
884             if (output)
885                 pdc_printf(p->out, "/%s", string);
886             break;
887 
888             case pdc_stringlist:
889             pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
890                         ann->hypertextcodepage, pdc_true, NULL, &string, NULL);
891             if (output)
892                 pdf_put_hypertext(p, string);
893             break;
894         }
895         if (output)
896             pdc_puts(p->out, "\n");
897     }
898 }
899 
900 
901 
902 static void
pdf_opt_alrdef(PDF * p,const char * keyword,pdf_annot * ann,int flag)903 pdf_opt_alrdef(PDF *p, const char *keyword, pdf_annot *ann, int flag)
904 {
905     if (ann->mask & flag)
906         pdc_error(p->pdc, PDF_E_ANN_OPTALRDEF, keyword, 0, 0, 0);
907 }
908 
909 static int
pdf_opt_effectless(PDF * p,const char * keyword,pdf_annottype curratype,pdf_annottype intendatypes)910 pdf_opt_effectless(PDF *p, const char *keyword, pdf_annottype curratype,
911                    pdf_annottype intendatypes)
912 {
913     if ((pdf_annottype) !(intendatypes & curratype))
914     {
915         const char *type = pdc_get_keyword(curratype, pdf_annottype_pdfkeylist);
916         pdc_warning(p->pdc, PDF_E_ANN_OPTEFFLESS_FORTYPE, keyword, type,
917                     0, 0);
918         return 1;
919     }
920     return 0;
921 }
922 
923 void
pdf__create_annotation(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * type,const char * optlist)924 pdf__create_annotation(PDF *p,
925      pdc_scalar llx, pdc_scalar lly, pdc_scalar urx, pdc_scalar ury,
926      const char *type, const char *optlist)
927 {
928     pdc_resopt *resopts = NULL;
929     pdc_clientdata cdata;
930     pdf_annottype atype;
931     pdf_annot *ann;
932     pdf_dest *dest = NULL;
933     const char *keyword, *keyword_s = NULL;
934     char **strlist = NULL;
935     pdc_scalar *line;
936     int i, j, k, ns, nss[2];
937     pdf_colortype maxcs = color_rgb;
938     pdf_ppt *ppt = p->curr_ppt;
939     pdc_matrix *ctm = &ppt->gstate[ppt->sl].ctm;
940 
941     pdc_check_number(p->pdc, "llx", llx);
942     pdc_check_number(p->pdc, "lly", lly);
943     pdc_check_number(p->pdc, "urx", urx);
944     pdc_check_number(p->pdc, "ury", ury);
945 
946     if (type == NULL || *type == '\0')
947         pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "type", 0, 0, 0);
948 
949     k = pdc_get_keycode_ci(type, pdf_annottype_pdfkeylist);
950     if (k == PDC_KEY_NOTFOUND)
951         pdc_error(p->pdc, PDC_E_ILLARG_STRING, "type", type, 0, 0);
952     atype = (pdf_annottype) k;
953 
954 
955     /* compatibility */
956     if (p->compatibility < PDC_1_5 &&
957         (atype == ann_polygon || atype == ann_polyline))
958     {
959         pdc_error(p->pdc, PDC_E_PAR_VERSION, type,
960                   pdc_get_pdfversion(p->pdc, PDC_1_5), 0, 0);
961     }
962 
963     if (p->compatibility >= PDC_1_6)
964         maxcs = color_cmyk;
965 
966     /* Parsing option list */
967     pdf_set_clientdata(p, &cdata);
968     resopts = pdc_parse_optionlist(p->pdc, optlist, pdf_create_annot_options,
969                                    &cdata, pdc_true);
970 
971     /* Initializing */
972     ann = pdf_new_annot(p, atype);
973 
974     keyword = "usercoordinates";
975     pdc_get_optvalues(keyword, resopts, &ann->usercoordinates, NULL);
976     pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
977 
978     ann->hypertextencoding =
979         pdf_get_hypertextencoding_opt(p, resopts, &ann->hypertextcodepage,
980                                       pdc_true);
981 
982     keyword = "custom";
983     ns = pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
984                  ann->hypertextcodepage, pdc_true, NULL, NULL, &ann->custom);
985     if (ns)
986     {
987         pdc_save_lastopt(resopts, PDC_OPT_SAVEALL);
988         ann->ncustoms = ns;
989         pdf_parse_and_write_annot_customlist(p, ann, pdc_false);
990     }
991 
992     keyword = "name";
993     ns = pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
994                  ann->hypertextcodepage, pdc_true, NULL, &ann->name, NULL);
995     if (ns)
996     {
997         pdf_opt_alrdef(p, keyword, ann, anndict_nm);
998         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
999     }
1000 
1001     keyword = "parentname";
1002     if (pdc_get_optvalues(keyword, resopts, NULL, NULL))
1003         ann->parentname = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1004 
1005     keyword = "popup";
1006     if (pdc_get_optvalues(keyword, resopts, NULL, NULL))
1007         ann->popup = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1008 
1009     keyword = "title";
1010     if (pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
1011                     ann->hypertextcodepage, pdc_true, NULL, &ann->title, NULL))
1012         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1013 
1014     keyword = "subject";
1015     if (pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
1016                   ann->hypertextcodepage, pdc_true, NULL, &ann->subject, NULL))
1017         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1018 
1019     keyword = "annotcolor";
1020     ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist);
1021     if (ns)
1022     {
1023         pdf_parse_coloropt(p, keyword, strlist, ns, (int) maxcs,
1024                            &ann->annotcolor);
1025     }
1026 
1027     keyword = "borderstyle";
1028     if (pdc_get_optvalues(keyword, resopts, &ns, NULL))
1029         ann->borderstyle = (pdf_borderstyle) ns;
1030 
1031     keyword = "dasharray";
1032     ns = pdc_get_optvalues(keyword, resopts, ann->dasharray, NULL);
1033     if (ns)
1034     {
1035         if (ns == 1)
1036             ann->dasharray[1] = ann->dasharray[0];
1037         if (ann->borderstyle != border_dashed)
1038             pdc_warning(p->pdc, PDC_E_OPT_IGNORED, keyword, 0, 0, 0);
1039     }
1040 
1041     keyword = "linewidth";
1042     pdc_get_optvalues(keyword, resopts, &ann->linewidth, NULL);
1043 
1044     keyword = "opacity";
1045     pdc_get_optvalues(keyword, resopts, &ann->opacity, NULL);
1046 
1047 
1048     keyword = "highlight";
1049     if (pdc_get_optvalues(keyword, resopts, &ns, NULL))
1050     {
1051         pdf_opt_effectless(p, keyword, atype, ann_link);
1052         ann->highlight = (pdf_highlight) ns;
1053     }
1054 
1055     keyword = "display";
1056     if (pdc_get_optvalues(keyword, resopts, &ann->display, NULL))
1057         ann->display = (pdf_display) ns;
1058 
1059     keyword = "zoom";
1060     pdc_get_optvalues(keyword, resopts, &ann->zoom, NULL);
1061 
1062     keyword = "rotate";
1063     pdc_get_optvalues(keyword, resopts, &ann->rotate, NULL);
1064 
1065     keyword = "readonly";
1066     pdc_get_optvalues(keyword, resopts, &ann->kreadonly, NULL);
1067 
1068     keyword = "locked";
1069     pdc_get_optvalues(keyword, resopts, &ann->locked, NULL);
1070 
1071     keyword = "open";
1072     if (pdc_get_optvalues(keyword, resopts, &ann->open, NULL))
1073     {
1074         pdf_opt_alrdef(p, keyword, ann, anndict_open);
1075         pdf_opt_effectless(p, keyword, atype,
1076                            (pdf_annottype) (ann_text | ann_popup));
1077     }
1078 
1079     keyword = "createdate";
1080     pdc_get_optvalues(keyword, resopts, &ann->createdate, NULL);
1081 
1082     keyword = "fillcolor";
1083     ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist);
1084     if (ns && !pdf_opt_effectless(p, keyword, atype, ann_freetext))
1085     {
1086         pdf_parse_coloropt(p, keyword, strlist, ns, (int) color_cmyk,
1087                            &ann->fillcolor);
1088     }
1089 
1090     keyword = "alignment";
1091     if (pdc_get_optvalues(keyword, resopts, &ns, NULL))
1092         ann->alignment = (pdf_quadding) ns;
1093 
1094     keyword = "font";
1095     if (pdc_get_optvalues(keyword, resopts, &ann->font, NULL))
1096         pdf_opt_effectless(p, keyword, atype, ann_freetext);
1097 
1098     keyword = "fontsize";
1099     if (pdf_get_fontsize_option(p, ann->font, resopts, &ann->fontsize))
1100     {
1101         pdf_opt_effectless(p, keyword, atype, ann_freetext);
1102         if (ann->usercoordinates == pdc_true)
1103             ann->fontsize = pdc_transform_scalar(ctm, ann->fontsize);
1104     }
1105 
1106     keyword = "orientate";
1107     if (pdc_get_optvalues(keyword, resopts, &ann->orientate, NULL))
1108         pdf_opt_effectless(p, keyword, atype,
1109                 (pdf_annottype) (ann_freetext | ann_stamp));
1110 
1111     keyword = "contents";
1112     if (atype == ann_freetext)
1113     {
1114         pdc_encoding enc = pdc_invalidenc;
1115         int codepage = 0;
1116 
1117         if (ann->font > -1)
1118         {
1119             enc = p->fonts[ann->font].ft.enc;
1120             codepage = p->fonts[ann->font].codepage;
1121         }
1122         pdf_get_opt_textlist(p, keyword, resopts, enc, codepage,
1123                              pdc_false, NULL, &ann->contents, NULL);
1124     }
1125     else
1126     {
1127         pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
1128                  ann->hypertextcodepage, pdc_true, NULL, &ann->contents, NULL);
1129     }
1130     if (ann->contents)
1131     {
1132         pdf_opt_alrdef(p, keyword, ann, anndict_contents);
1133         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1134     }
1135 
1136     keyword = "destination";
1137     if (pdc_get_optvalues(keyword, resopts, NULL, &strlist) &&
1138         !pdf_opt_effectless(p, keyword, atype, ann_link))
1139     {
1140         ann->dest = pdf_parse_destination_optlist(p, strlist[0], 0,
1141                         pdf_locallink);
1142         keyword_s = keyword;
1143     }
1144     else
1145     {
1146         keyword = "destname";
1147         if (atype == ann_link)
1148             dest = pdf_get_option_destname(p, resopts, ann->hypertextencoding,
1149                                            ann->hypertextcodepage);
1150         else if (pdc_get_optvalues(keyword, resopts, NULL, NULL))
1151             pdf_opt_effectless(p, keyword, atype, ann_link);
1152         if (dest)
1153         {
1154             ann->dest = dest;
1155             keyword_s = keyword;
1156         }
1157     }
1158 
1159     keyword = "filename";
1160     if (pdc_get_optvalues(keyword, resopts, NULL, NULL) &&
1161         !pdf_opt_effectless(p, keyword, atype,
1162                            (pdf_annottype) (ann_fileattachment | ann_movie)))
1163     {
1164         /* DON'T change order */
1165 
1166         /* native filename */
1167         ann->nativefilename = pdf_get_opt_filename(p, keyword, resopts,
1168                           ann->hypertextencoding, ann->hypertextcodepage);
1169 
1170         pdf_get_opt_textlist(p, keyword, resopts, ann->hypertextencoding,
1171                              ann->hypertextcodepage,
1172              /* bug #2344 */ atype == ann_fileattachment ? pdc_undef : pdc_true,
1173                              NULL, &ann->filename, NULL);
1174         pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1175 
1176         if (atype == ann_fileattachment)
1177             ann->filesize = pdf_check_file(p, ann->filename, pdc_true);
1178     }
1179 
1180     keyword = "mimetype";
1181     if (pdc_get_optvalues(keyword, resopts, NULL, NULL) &&
1182         !pdf_opt_effectless(p, keyword, atype, ann_fileattachment))
1183         ann->mimetype = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1184 
1185     keyword = "iconname";
1186     if (pdc_get_optvalues(keyword, resopts, NULL, &strlist) &&
1187         !pdf_opt_effectless(p, keyword, atype,
1188                 (pdf_annottype) (ann_text | ann_stamp | ann_fileattachment)))
1189     {
1190         const pdc_keyconn *kc = pdf_text_iconnames_pdfkeylist;
1191 
1192         pdf_opt_alrdef(p, keyword, ann, anndict_name);
1193 
1194         if (atype == ann_stamp)
1195             kc = pdf_stamp_iconnames_pdfkeylist;
1196         else if (atype == ann_fileattachment)
1197             kc = pdf_attach_iconnames_pdfkeylist;
1198 
1199         ann->iconname = pdc_get_int_keyword(strlist[0], kc);
1200         if (ann->iconname == NULL)
1201             pdc_error(p->pdc, PDC_E_OPT_ILLKEYWORD, keyword, strlist[0],
1202                       0, 0);
1203     }
1204 
1205     keyword = "endingstyles";
1206     if (pdc_get_optvalues(keyword, resopts, nss, NULL))
1207     {
1208         ann->endingstyles[0] = (pdf_endingstyles) nss[0];
1209         ann->endingstyles[1] = (pdf_endingstyles) nss[1];
1210         pdf_opt_effectless(p, keyword, atype,
1211                            (pdf_annottype) (ann_line | ann_polyline));
1212     }
1213 
1214     keyword = "interiorcolor";
1215     ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist);
1216     if (ns && !pdf_opt_effectless(p, keyword, atype,
1217                 (pdf_annottype) (ann_line | ann_polyline |
1218                                  ann_square | ann_circle)))
1219     {
1220         pdf_parse_coloropt(p, keyword, strlist, ns, (int) maxcs,
1221                            &ann->interiorcolor);
1222     }
1223 
1224     keyword = "cloudy";
1225     if (pdc_get_optvalues(keyword, resopts, &ann->cloudy, NULL))
1226         pdf_opt_effectless(p, keyword, atype, ann_polygon);
1227 
1228     keyword = "line";
1229     ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist);
1230     if (ns && !pdf_opt_effectless(p, keyword, atype, ann_line))
1231     {
1232         line = (pdc_scalar *) strlist;
1233         if (ann->usercoordinates == pdc_true)
1234         {
1235             pdc_transform_point(ctm, line[0], line[1], &line[0], &line[1]);
1236             pdc_transform_point(ctm, line[2], line[3], &line[2], &line[3]);
1237         }
1238         ann->line = (pdc_scalar *) pdc_save_lastopt(resopts, PDC_OPT_SAVEALL);
1239     }
1240 
1241     keyword = "polylinelist";
1242     ns = pdc_get_optvalues(keyword, resopts, NULL, &strlist);
1243     if (ns)
1244     {
1245         if (!pdf_opt_effectless(p, keyword, atype,
1246                (pdf_annottype) (ann_ink | ann_polygon | ann_polyline |
1247                                 ann_highlight | ann_underline |
1248                                 ann_squiggly | ann_strikeout)))
1249         {
1250             pdc_polyline *pl = (pdc_polyline *) strlist;
1251 
1252             for (j = 0; j < ns; j++)
1253             {
1254                 if (pl[j].np < 2 ||
1255                     (atype != ann_ink && atype != ann_polygon &&
1256                      atype != ann_polyline && pl[j].np != 4))
1257                 {
1258                     pdc_error(p->pdc, PDF_E_ANN_BADNUMCOORD, keyword, 0, 0, 0);
1259                 }
1260                 for (i = 0; i < pl[j].np; i++)
1261                 {
1262                     if (ann->usercoordinates == pdc_true)
1263                         pdc_transform_vector(ctm, &pl[j].p[i], NULL);
1264                 }
1265             }
1266             pdc_delete_polylinelist(p->pdc, ann->polylinelist, ann->nplines);
1267             ann->polylinelist = pl;
1268             ann->nplines = ns;
1269             pdc_save_lastopt(resopts, PDC_OPT_SAVEALL);
1270         }
1271     }
1272     else
1273         pdf_permute_coordinates(ann, atype);
1274 
1275     keyword = "action";
1276     if (pdc_get_optvalues(keyword, resopts, NULL, &strlist))
1277     {
1278         /*
1279          * PDF 1.7 allows the A action dictionary only for annotation types
1280          * link, widget and screen. Widget is handled elsewhere, and screen
1281          * is not yet implemented, so only link is allowed with compatiblity
1282          * 1.7.
1283          * Must be extended that also screen annotation is accepted here
1284          * once it is implemented.
1285          */
1286         if (p->compatibility >= PDC_1_7)
1287         {
1288             if (ann->atype != ann_link)
1289             {
1290                 pdc_error(p->pdc, PDF_E_ANN_ACTIONNOTALLOWED,
1291                         pdc_get_keyword(ann->atype, pdf_annottype_pdfkeylist),
1292                         0, 0, 0);
1293             }
1294         }
1295 
1296         if (ann->dest)
1297         {
1298             pdf_cleanup_destination(p, ann->dest);
1299             ann->dest = NULL;
1300             pdc_warning(p->pdc, PDC_E_OPT_IGNORE, keyword_s, keyword, 0, 0);
1301         }
1302 
1303         /* parsing of action list */
1304         pdf_parse_and_write_actionlist(p, event_annotation, NULL,
1305                                        (const char *) strlist[0]);
1306         ann->action = (char *) pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM);
1307     }
1308 
1309 
1310 
1311     keyword = "movieposter";
1312     if (pdc_get_optvalues(keyword, resopts, &ns, NULL))
1313     {
1314         pdf_opt_effectless(p, keyword, atype, ann_movie);
1315         if (ns < 0)
1316         {
1317             ann->movieposter = (pdc_id) ns;
1318         }
1319         else
1320         {
1321 #if 0
1322             int cstype = pdf_get_image_colorspace(p, ns);
1323 
1324             if (cstype != (int) DeviceGray && cstype != (int) DeviceRGB)
1325                 pdc_error(p->pdc, PDF_E_ANN_ILLTEMPLATE, 0, 0, 0, 0);
1326 #endif
1327             ann->movieposter = pdf_get_xobject(p, ns);
1328         }
1329     }
1330 
1331     keyword = "showcontrols";
1332     if (pdc_get_optvalues(keyword, resopts, &ann->showcontrols, NULL))
1333         pdf_opt_effectless(p, keyword, atype, ann_movie);
1334 
1335     keyword = "playmode";
1336     if (pdc_get_optvalues(keyword, resopts, &ns, NULL))
1337     {
1338         pdf_opt_effectless(p, keyword, atype, ann_movie);
1339         ann->playmode = (pdf_playmode_states) ns;
1340     }
1341 
1342     keyword = "windowscale";
1343     if (pdc_get_optvalues(keyword, resopts, &ann->windowscale, NULL))
1344         pdf_opt_effectless(p, keyword, atype, ann_movie);
1345 
1346     keyword = "windowposition";
1347     ns = pdc_get_optvalues(keyword, resopts, ann->windowposition, NULL);
1348     if (ns)
1349     {
1350         pdf_opt_effectless(p, keyword, atype, ann_movie);
1351         pdf_set_position_values(p, ann->windowposition, ns);
1352     }
1353 
1354     keyword = "soundvolume";
1355     if (pdc_get_optvalues(keyword, resopts, &ann->soundvolume, NULL))
1356         pdf_opt_effectless(p, keyword, atype, ann_movie);
1357 
1358     /* named annotation, to be accessible by a GoTo3DView or Movie action */
1359     if ((atype == ann_3d || atype == ann_movie) && ann->name != NULL)
1360     {
1361         char *name = (char *) pdc_strdup(p->pdc, ann->name);
1362 
1363         ann->obj_id = pdc_alloc_id(p->out);
1364         pdf_insert_name(p, name, names_annots, ann->obj_id);
1365     }
1366 
1367     /* work-around for Acrobat 8 (see bug #1225) */
1368     if (ann->annotcolor.type == (int) color_none &&
1369         (atype == ann_square || atype == ann_circle))
1370     {
1371         ann->annotcolor.type = (int) color_rgb;
1372         ann->annotcolor.value[0] = 1.0;
1373         ann->annotcolor.value[1] = 1.0;
1374         ann->annotcolor.value[2] = 1.0;
1375     }
1376 
1377     /* required options */
1378     keyword = NULL;
1379     if (ann->contents == NULL &&
1380         atype != ann_link && atype != ann_popup && atype != ann_movie)
1381         keyword = "contents";
1382     if (ann->fontsize == 0 && atype == ann_freetext)
1383         keyword = "fontsize";
1384     if (ann->font == -1 && atype == ann_freetext)
1385         keyword = "font";
1386     if (ann->filename == NULL &&
1387         (atype == ann_fileattachment || atype == ann_movie))
1388         keyword = "filename";
1389     if (ann->line == NULL && atype == ann_line)
1390         keyword = "line";
1391     if (ann->polylinelist == NULL &&
1392         (atype == ann_ink || atype == ann_polygon || atype == ann_polyline))
1393         keyword = "polylinelist";
1394 
1395     if (keyword)
1396         pdc_error(p->pdc, PDC_E_OPT_NOTFOUND, keyword, 0, 0, 0);
1397 
1398 
1399     if (atype == ann_freetext)
1400     {
1401         pdf_font *font_s = &p->fonts[ann->font];
1402         const char *fontname =
1403             pdc_errprintf(p->pdc, "%.*s", PDC_ERR_MAXSTRLEN, font_s->ft.name);
1404 
1405         if (!strcmp(pdf_get_pdf_fontname(font_s), fontname))
1406             pdc_error(p->pdc, PDF_E_ANN_NOSTDFONT, fontname, 0, 0, 0);
1407     }
1408 
1409     /*
1410      * matchbox available
1411      */
1412     keyword = "usematchbox";
1413     if (pdc_get_optvalues(keyword, resopts, NULL, &strlist))
1414     {
1415         pdf_annot *ann_first = ann;
1416         const char *mboxname;
1417         int ir, nrect, irect;
1418 
1419         mboxname = pdf_get_usematchbox(p, keyword, strlist[0], &irect, &nrect);
1420         if (mboxname != NULL)
1421         {
1422             if (irect > nrect)
1423             {
1424                 pdf_delete_last_annot(p);
1425             }
1426             else
1427             {
1428                 pdf_mbox *mbox;
1429                 pdc_vector pl[5];
1430 
1431                 /* rectangle loop */
1432                 for (ir = irect; ir <= nrect; ir++)
1433                 {
1434                     if (ir > irect)
1435                     {
1436                         /* create copy */
1437                         ann = pdf_new_annot(p, atype);
1438                         memcpy(ann, ann_first, sizeof(pdf_annot));
1439                         ann->obj_id = PDC_BAD_ID;
1440                         ann->iscopy = pdc_true;
1441                         ann->nplines = 0;
1442                         ann->polylinelist = NULL;
1443                     }
1444 
1445                     /* rectangle #ir */
1446                     mbox = pdf_get_mbox(p, NULL, mboxname, ir, NULL);
1447                     pdf_get_mbox_rectangle(p, mbox, pl);
1448                     pdf_init_rectangle(p, ann, 0, 0, 0, 0, pl);
1449                     pdf_permute_coordinates(ann, atype);
1450                     ann->usercoordinates = pdc_true;
1451                 }
1452             }
1453         }
1454     }
1455 
1456 }
1457 
1458 pdc_id
pdf_write_annots_root(PDF * p,pdc_vtr * annots,pdf_widget * widgetlist)1459 pdf_write_annots_root(PDF *p, pdc_vtr *annots, pdf_widget *widgetlist)
1460 {
1461     pdc_id result = PDC_BAD_ID;
1462 
1463     /* Annotations array */
1464     if (annots != NULL || widgetlist)
1465     {
1466         result = pdc_begin_obj(p->out, PDC_NEW_ID);
1467 	pdc_begin_array(p->out);
1468 
1469         if (annots != NULL)
1470         {
1471             pdf_annot *ann;
1472             int i, na = pdc_vtr_size(annots);
1473 
1474             for (i = 0; i < na; i++)
1475             {
1476                 ann = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot);
1477                 if (ann->obj_id == PDC_BAD_ID)
1478                     ann->obj_id = pdc_alloc_id(p->out);
1479                 pdc_objref_c(p->out, ann->obj_id);
1480             }
1481         }
1482 
1483         (void) widgetlist;
1484 
1485 	pdc_end_array(p->out);
1486 	pdc_end_obj(p->out);
1487     }
1488 
1489     return result;
1490 }
1491 
1492 static void
pdf_write_defappstring(PDF * p,pdf_annot * ann)1493 pdf_write_defappstring(PDF *p, pdf_annot *ann)
1494 {
1495     char buf[PDC_GEN_BUFSIZE], *bufc;
1496     pdf_coloropt *fs;
1497     int ct;
1498 
1499     if (ann->font == -1)
1500         return;
1501 
1502     bufc = buf;
1503 
1504     /* font and fontsize */
1505     bufc +=  pdc_sprintf(p->pdc, pdc_true, bufc, "/%s %f Tf",
1506                          pdf_get_pdf_fontname(&p->fonts[ann->font]),
1507                          ann->fontsize);
1508 
1509     /* fill and stroke color */
1510     fs = &ann->fillcolor;
1511     ct = fs->type;
1512     switch (ct)
1513     {
1514         case color_gray:
1515         bufc +=  pdc_sprintf(p->pdc, pdc_true, bufc, " %f g",
1516                              fs->value[0]);
1517         break;
1518 
1519         case color_rgb:
1520         bufc +=  pdc_sprintf(p->pdc, pdc_true, bufc, " %f %f %f rg",
1521                              fs->value[0], fs->value[1], fs->value[2]);
1522         break;
1523 
1524         case color_cmyk:
1525         bufc +=  pdc_sprintf(p->pdc, pdc_true, bufc, " %f %f %f %f k",
1526                              fs->value[0], fs->value[1],
1527                              fs->value[2], fs->value[3]);
1528         break;
1529     }
1530 
1531     pdc_puts(p->out, "/DA");
1532     pdf_put_hypertext(p, buf);
1533     pdc_puts(p->out, "\n");
1534 }
1535 
1536 static void
pdf_write_colorentry(PDF * p,const char * keyname,pdf_coloropt * coloropt)1537 pdf_write_colorentry(PDF *p, const char *keyname, pdf_coloropt *coloropt)
1538 {
1539     if (p->compatibility < PDC_1_6)
1540     {
1541         if (coloropt->type != (int) color_none)
1542         {
1543             pdc_printf(p->out, "%s[%f %f %f]\n",
1544                        keyname,
1545                        coloropt->value[0],
1546                        coloropt->value[1],
1547                        coloropt->value[2]);
1548         }
1549     }
1550     else
1551     {
1552         switch (coloropt->type)
1553         {
1554             case color_none:
1555             /* this doesn't work in Acrobat 8
1556             pdc_printf(p->out, "%s[0]\n",
1557                        keyname);
1558             */
1559             break;
1560 
1561             case color_gray:
1562             pdc_printf(p->out, "%s[%f]\n",
1563                        keyname,
1564                        coloropt->value[0]);
1565             break;
1566 
1567             case color_rgb:
1568             pdc_printf(p->out, "%s[%f %f %f]\n",
1569                        keyname,
1570                        coloropt->value[0],
1571                        coloropt->value[1],
1572                        coloropt->value[2]);
1573             break;
1574 
1575             case color_cmyk:
1576             pdc_printf(p->out, "%s[%f %f %f %f]\n",
1577                        keyname,
1578                        coloropt->value[0],
1579                        coloropt->value[1],
1580                        coloropt->value[2],
1581                        coloropt->value[3]);
1582             break;
1583         }
1584     }
1585 }
1586 
1587 void
pdf_write_page_annots(PDF * p,pdc_vtr * annots)1588 pdf_write_page_annots(PDF *p, pdc_vtr *annots)
1589 {
1590     pdf_annot *ann, *annpar;
1591     pdc_id act_idlist[PDF_MAX_EVENTS];
1592     int i, j, k, na, flags;
1593 
1594     na = pdc_vtr_size(annots);
1595 
1596     for (k = 0; k < na; k++)
1597     {
1598         ann = (pdf_annot *) &pdc_vtr_at(annots, k, pdf_annot);
1599 
1600 
1601         /* write action objects */
1602         if (ann->action)
1603             pdf_parse_and_write_actionlist(p, event_annotation, act_idlist,
1604                                            (const char *) ann->action);
1605 
1606 
1607         pdc_begin_obj(p->out, ann->obj_id);     /* Annotation object */
1608         pdc_begin_dict(p->out);                 /* Annotation dict */
1609 
1610         pdc_puts(p->out, "/Type/Annot\n");
1611         pdc_printf(p->out, "/Subtype/%s\n",
1612                    pdc_get_keyword(ann->atype, pdf_annottype_pdfkeylist));
1613 
1614 
1615 
1616 
1617         /* Contents */
1618         if (ann->contents)
1619         {
1620             pdc_puts(p->out, "/Contents");
1621             if (ann->atype == ann_freetext)
1622                 pdf_put_fieldtext(p, ann->contents, ann->font);
1623             else
1624                 pdf_put_hypertext(p, ann->contents);
1625             pdc_puts(p->out, "\n");
1626         }
1627 
1628         /* Current Page */
1629 	pdc_objref(p->out, "/P", pdf_get_page_id(p, 0));
1630 
1631         /* Rectangle */
1632         pdc_printf(p->out, "/Rect[%f %f %f %f]\n",
1633             ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury);
1634 
1635         /* Name */
1636         if (ann->name)
1637         {
1638             pdc_puts(p->out, "/NM");
1639             pdf_put_hypertext(p, ann->name);
1640             pdc_puts(p->out, "\n");
1641         }
1642 
1643         /* Flags */
1644         flags = 0;
1645         if (ann->display != disp_noprint)
1646         {
1647             flags = (1<<2);
1648             flags |= ann->display;
1649         }
1650         if (!ann->zoom)
1651             flags |= (1<<3);
1652         if (!ann->rotate)
1653             flags |= (1<<4);
1654         if (ann->kreadonly)
1655             flags |= (1<<6);
1656         if (ann->locked)
1657             flags |= (1<<7);
1658         if (flags)
1659             pdc_printf(p->out, "/F %d\n", flags);
1660 
1661         /* Border style dictionary */
1662         if (ann->linewidth != 1 || ann->borderstyle != border_solid)
1663         {
1664             pdc_puts(p->out, "/BS");
1665             pdc_begin_dict(p->out);             /* BS dict */
1666 
1667             pdc_printf(p->out, "/W %d", ann->linewidth);
1668             pdc_printf(p->out, "/S/%s",
1669                 pdc_get_keyword(ann->borderstyle, pdf_borderstyle_pdfkeylist));
1670             if (ann->borderstyle == border_dashed)
1671                 pdc_printf(p->out, "/D[%f %f]",
1672                            ann->dasharray[0], ann->dasharray[1]);
1673 
1674             pdc_end_dict(p->out);               /* BS dict */
1675 
1676             /* Write the Border key in old-style PDF 1.1 format
1677              * because of a bug in PDF 1.4 and earlier
1678              */
1679             pdc_printf(p->out, "/Border[0 0 %f", (double) ann->linewidth);
1680 
1681             if (ann->borderstyle == border_dashed)
1682                 pdc_printf(p->out, "[%f %f]",
1683                            ann->dasharray[0], ann->dasharray[1]);
1684             pdc_puts(p->out, "]\n");
1685         }
1686 
1687         /* Annotation color */
1688         pdf_write_colorentry(p, "/C", &ann->annotcolor);
1689 
1690         /* Title */
1691         if (ann->title && *ann->title)
1692         {
1693             pdc_puts(p->out, "/T");
1694             pdf_put_hypertext(p, ann->title);
1695             pdc_puts(p->out, "\n");
1696         }
1697 
1698         /* Subject */
1699         if (ann->subject && *ann->subject)
1700         {
1701             pdc_puts(p->out, "/Subj");
1702             pdf_put_hypertext(p, ann->subject);
1703             pdc_puts(p->out, "\n");
1704         }
1705 
1706         /* Popup */
1707         if (ann->popup && *ann->popup)
1708         {
1709             for (i = 0; i < na; i++)
1710             {
1711                 annpar = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot);
1712                 if (annpar->name != NULL &&
1713                     !strcmp(ann->popup, annpar->name))
1714                 {
1715 		    pdc_objref(p->out, "/Popup", annpar->obj_id);
1716                     break;
1717                 }
1718             }
1719         }
1720 
1721         /* Icon Name */
1722         if (ann->iconname && *ann->iconname)
1723             pdc_printf(p->out, "/Name/%s\n", ann->iconname);
1724 
1725         /* CreationDate */
1726         if (ann->createdate)
1727         {
1728             char time_str[PDC_TIME_SBUF_SIZE];
1729 
1730             pdc_get_timestr(time_str, pdc_false);
1731             pdc_puts(p->out, "/CreationDate ");
1732             pdf_put_hypertext(p, time_str);
1733             pdc_puts(p->out, "\n");
1734         }
1735 
1736         /* Opacity */
1737         if (ann->opacity != 1)
1738             pdc_printf(p->out, "/CA %f\n", ann->opacity);
1739 
1740         /* write Action entries */
1741         if (ann->action)
1742             pdf_write_action_entries(p, event_annotation, act_idlist);
1743 
1744         /* custom entries */
1745         pdf_parse_and_write_annot_customlist(p, ann, pdc_true);
1746 
1747         switch (ann->atype)
1748         {
1749             /* Open */
1750             case ann_text:
1751             case ann_popup:
1752             if (ann->open)
1753                 pdc_puts(p->out, "/Open true\n");
1754             break;
1755 
1756             /* Alignment, Default appearance string */
1757             case ann_freetext:
1758             if (ann->alignment != quadd_left)
1759                 pdc_printf(p->out, "/Q %d\n", ann->alignment);
1760             pdf_write_defappstring(p, ann);
1761             break;
1762 
1763             /* Line */
1764             case ann_line:
1765             pdc_printf(p->out, "/L[%f %f %f %f]\n",
1766                        ann->line[0], ann->line[1], ann->line[2], ann->line[3]);
1767             break;
1768 
1769             /* InkList, QuadPoints and Vertices */
1770             case ann_link:
1771             if (!ann->usercoordinates || p->compatibility < PDC_1_6)
1772                 break;
1773             case ann_highlight:
1774             case ann_underline:
1775             case ann_squiggly:
1776             case ann_strikeout:
1777             ann->polylinelist[0].np = 4;  /* because of Acrobat error */
1778             case ann_ink:
1779             case ann_polygon:
1780             case ann_polyline:
1781             pdc_printf(p->out, "/%s",
1782                        pdc_get_keyword(ann->atype, pdf_polyline_pdfkeylist));
1783 	    pdc_begin_array(p->out);
1784             for (i = 0; i < ann->nplines; i++)
1785             {
1786                 if (ann->atype == ann_ink)
1787 		    pdc_begin_array(p->out);
1788                 for (j = 0; j < ann->polylinelist[i].np; j++)
1789                      pdc_printf(p->out, "%f %f ", ann->polylinelist[i].p[j].x,
1790                                                   ann->polylinelist[i].p[j].y);
1791                 if (ann->atype == ann_ink)
1792 		    pdc_end_array_c(p->out);
1793             }
1794 	    pdc_end_array(p->out);
1795             break;
1796 
1797             default:
1798             break;
1799         }
1800 
1801         switch (ann->atype)
1802         {
1803             /* Destination, Highlight */
1804             case ann_link:
1805             if (ann->dest)
1806             {
1807                 pdc_puts(p->out, "/Dest");
1808                 pdf_write_destination(p, ann->dest);
1809             }
1810             if (ann->highlight != high_invert)
1811                 pdc_printf(p->out, "/H/%s\n",
1812                     pdc_get_keyword(ann->highlight, pdf_highlight_pdfkeylist));
1813             break;
1814 
1815             /* Line ending styles */
1816             case ann_line:
1817             case ann_polyline:
1818             if (ann->endingstyles[0] != line_none ||
1819                 ann->endingstyles[1] != line_none)
1820                 pdc_printf(p->out, "/LE[/%s /%s]\n",
1821                     pdc_get_keyword(ann->endingstyles[0],
1822                                     pdf_endingstyles_pdfkeylist),
1823                     pdc_get_keyword(ann->endingstyles[1],
1824                                     pdf_endingstyles_pdfkeylist));
1825             break;
1826 
1827             /* border effect dictionary */
1828             case ann_polygon:
1829             if (ann->cloudy > -1)
1830             {
1831                 pdc_puts(p->out, "/BE");
1832                 pdc_begin_dict(p->out);                 /* BE dict */
1833                 pdc_puts(p->out, "/S/C");
1834                 if (ann->cloudy > 0)
1835                     pdc_printf(p->out, "/I %f", ann->cloudy);
1836                 pdc_end_dict(p->out);                   /* BE dict */
1837             }
1838 
1839             /* rotate */
1840             case ann_stamp:
1841             case ann_freetext:
1842             if (ann->orientate)
1843                 pdc_printf(p->out, "/Rotate %d\n", ann->orientate);
1844             break;
1845 
1846             default:
1847             break;
1848         }
1849 
1850         switch (ann->atype)
1851         {
1852             /* Interior color */
1853             case ann_line:
1854             case ann_polyline:
1855             case ann_square:
1856             case ann_circle:
1857             pdf_write_colorentry(p, "/IC", &ann->interiorcolor);
1858             break;
1859 
1860             /* Parent Annotation */
1861             case ann_popup:
1862             if (ann->parentname && *ann->parentname)
1863             {
1864                 for (i = 0; i < na; i++)
1865                 {
1866                     annpar = (pdf_annot *) &pdc_vtr_at(annots, i, pdf_annot);
1867                     if (annpar->name != NULL &&
1868                         !strcmp(ann->parentname, annpar->name))
1869                     {
1870 			pdc_objref(p->out, "/Parent", annpar->obj_id);
1871                         break;
1872                     }
1873                 }
1874             }
1875             break;
1876 
1877             /* File specification */
1878             case ann_fileattachment:
1879             {
1880                 /* see bug #1439 */
1881                 const char *basename = pdc_file_strip_dirs(ann->nativefilename);
1882 
1883                 pdc_puts(p->out, "/FS");
1884                 pdc_begin_dict(p->out);                 /* FS dict */
1885                 pdc_puts(p->out, "/Type/Filespec\n");
1886                 pdc_puts(p->out, "/F");
1887                 pdf_put_pdffilename(p, basename);
1888                 pdc_puts(p->out, "\n");
1889                 if (p->compatibility >= PDC_1_7)
1890                 {
1891                     pdc_puts(p->out, "/UF");
1892                     pdf_put_pdfunifilename(p, basename);
1893                     pdc_puts(p->out, "\n");
1894                 }
1895 
1896                 /* alloc id for the actual embedded file stream */
1897                 ann->obj_id = pdc_alloc_id(p->out);
1898                 pdc_puts(p->out, "/EF");
1899                 pdc_begin_dict(p->out);
1900                 pdc_objref(p->out, "/F", ann->obj_id);
1901                 pdc_end_dict(p->out);
1902                 pdc_end_dict(p->out);                   /* FS dict */
1903             }
1904             break;
1905 
1906 
1907             case ann_movie:
1908             {
1909                 pdc_puts(p->out, "/Movie");
1910                 pdc_begin_dict(p->out);                 /* Movie dict */
1911 
1912                 /* File specification */
1913                 pdc_puts(p->out, "/F");
1914                 pdc_begin_dict(p->out);                 /* F dict */
1915                 pdc_puts(p->out, "/Type/Filespec\n");
1916                 pdc_puts(p->out, "/F");
1917                 pdf_put_pdffilename(p, ann->nativefilename);
1918                 pdc_puts(p->out, "\n");
1919                 if (p->compatibility >= PDC_1_7)
1920                 {
1921                     pdc_puts(p->out, "/UF");
1922                     pdf_put_pdfunifilename(p, ann->filename);
1923                     pdc_puts(p->out, "\n");
1924                 }
1925                 pdc_end_dict(p->out);                   /* F dict */
1926 
1927                 /* Aspect - not supported by Acrobat */
1928                 /* Rotate - doesn't work */
1929 
1930                 /* Poster */
1931                 if (ann->movieposter != movieposter_none)
1932                 {
1933                     if (ann->movieposter == movieposter_auto)
1934                         pdc_puts(p->out, "/Poster true");
1935                     else
1936                         pdc_objref(p->out, "/Poster", ann->movieposter);
1937                 }
1938 
1939                 pdc_end_dict(p->out);                   /* Movie dict */
1940 
1941                 if (ann->soundvolume != 1.0 ||
1942                     ann->showcontrols ||
1943                     ann->playmode != playmode_once ||
1944                     ann->windowscale != 0)
1945                 {
1946                     pdc_puts(p->out, "/A");
1947                     pdc_begin_dict(p->out);             /* Activation dict */
1948 
1949                     /* Start, Duration, Rate, Synchronus - not supported */
1950 
1951                     /* Volume */
1952                     if (ann->soundvolume != 1.0)
1953                         pdc_printf(p->out, "/Volume %f\n", ann->soundvolume);
1954 
1955                     /* ShowControls */
1956                     if (ann->showcontrols)
1957                         pdc_puts(p->out, "/ShowControls true\n");
1958 
1959                     /* Mode */
1960                     if (ann->playmode != playmode_once)
1961                         pdc_printf(p->out, "/Mode/%s\n",
1962                                    pdc_get_keyword(ann->playmode,
1963                                                    pdf_playmode_pdfkeylist));
1964 
1965                     /* window */
1966                     if (ann->windowscale != 0)
1967                     {
1968                         int sx, sy;
1969 
1970                         if (ann->windowscale == PDF_ANN_FULLSCREEN)
1971                         {
1972                             /* see PDF Reference 1.7, Appendix H, 153. */
1973                             sx = 999;
1974                             sy = 1;
1975                         }
1976                         else
1977                         {
1978                             pdc_scalar sf, sp;
1979 
1980                             sp = 1;
1981                             for (i = 0; ; i++)
1982                             {
1983                                 sf = sp * ann->windowscale;
1984                                 if (sf == (double) (int) (sf) || i == 5)
1985                                     break;
1986                                 sp *= 10;
1987                             }
1988 
1989                             sx = (int) sf;
1990                             sy = (int) sp;
1991                         }
1992 
1993                         /* FWScale */
1994                         pdc_printf(p->out, "/FWScale[%d %d]\n", sx, sy);
1995 
1996                         /* FWPosition */
1997                         if (ann->windowposition[0] != 50.0 ||
1998                             ann->windowposition[1] != 50.0)
1999                         {
2000                             pdc_printf(p->out, "/FWPosition[%f %f]\n",
2001                                        ann->windowposition[0] / 100.0,
2002                                        1.0 - ann->windowposition[1] / 100.0);
2003                         }
2004                     }
2005 
2006                     pdc_end_dict(p->out);               /* Activation dict */
2007                 }
2008             }
2009             break;
2010 
2011             default:
2012             break;
2013         }
2014 
2015 
2016         pdc_end_dict(p->out);                   /* Annotation dict */
2017         pdc_end_obj(p->out);                    /* Annotation object */
2018     }
2019 
2020     /* Write the actual embedded files with preallocated ids */
2021     for (k = 0; k < na; k++)
2022     {
2023         ann = (pdf_annot *) &pdc_vtr_at(annots, k, pdf_annot);
2024         if (ann->atype == ann_fileattachment)
2025             pdf_embed_file(p, ann->obj_id, ann->filename, ann->mimetype,
2026                            ann->filesize);
2027     }
2028 }
2029 
2030 /*****************************************************************************/
2031 /**            deprecated historical annotation functions                   **/
2032 /*****************************************************************************/
2033 
2034 void
pdf_create_link(PDF * p,const char * type,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * annopts,const char * utext,int len)2035 pdf_create_link(
2036     PDF *p,
2037     const char *type,
2038     pdc_scalar llx,
2039     pdc_scalar lly,
2040     pdc_scalar urx,
2041     pdc_scalar ury,
2042     const char *annopts,
2043     const char *utext,
2044     int len)
2045 {
2046     static const char *fn = "pdf_create_link";
2047     char *optlist;
2048     char *name;
2049     int acthdl;
2050 
2051     name = pdf_convert_name(p, utext, len, PDC_CONV_WITHBOM);
2052     optlist = (char *) pdc_malloc(p->pdc, strlen(name) + 80, fn);
2053 
2054     if (!pdc_stricmp(type, "URI"))
2055         strcpy(optlist, "url {");
2056     else if (!pdc_stricmp(type, "GoTo"))
2057         strcpy(optlist, "destname {");
2058     else if (!pdc_stricmp(type, "GoToR"))
2059         strcpy(optlist, "destination {page 1} filename {");
2060     strcat(optlist, name);
2061     strcat(optlist, "}");
2062 
2063     acthdl = pdf__create_action(p, type, optlist);
2064     if (acthdl > -1)
2065     {
2066         if (p->pdc->hastobepos) acthdl++;
2067         pdc_sprintf(p->pdc, pdc_false, optlist,
2068                     "action {activate %d} usercoordinates ", acthdl);
2069         strcat(optlist, annopts);
2070         pdf__create_annotation(p, llx, lly, urx, ury, "Link", optlist);
2071     }
2072 
2073     pdc_free(p->pdc, optlist);
2074     pdc_free(p->pdc, name);
2075 }
2076 
2077 void
pdf_init_annot_params(PDF * p)2078 pdf_init_annot_params(PDF *p)
2079 {
2080     /* annotation border style defaults */
2081     p->border_style = border_solid;
2082     p->border_width = 1;
2083     p->border_red = 0;
2084     p->border_green = 0;
2085     p->border_blue = 0;
2086     p->border_dash1 = 3;
2087     p->border_dash2 = 3;
2088 
2089     /* auxiliary function parameters */
2090     p->launchlink_parameters = NULL;
2091     p->launchlink_operation = NULL;
2092     p->launchlink_defaultdir = NULL;
2093 }
2094 
2095 void
pdf_cleanup_annot_params(PDF * p)2096 pdf_cleanup_annot_params(PDF *p)
2097 {
2098     if (p->launchlink_parameters)
2099     {
2100         pdc_free(p->pdc, p->launchlink_parameters);
2101         p->launchlink_parameters = NULL;
2102     }
2103 
2104     if (p->launchlink_operation)
2105     {
2106         pdc_free(p->pdc, p->launchlink_operation);
2107         p->launchlink_operation = NULL;
2108     }
2109 
2110     if (p->launchlink_defaultdir)
2111     {
2112         pdc_free(p->pdc, p->launchlink_defaultdir);
2113         p->launchlink_defaultdir = NULL;
2114     }
2115 }
2116 
2117 static void
pdf_insert_annot_params(PDF * p,pdf_annot * ann)2118 pdf_insert_annot_params(PDF *p, pdf_annot *ann)
2119 {
2120     ann->borderstyle = p->border_style;
2121     ann->linewidth = (int) p->border_width;
2122     ann->annotcolor.type = (int) color_rgb;
2123     ann->annotcolor.value[0] = p->border_red;
2124     ann->annotcolor.value[1] = p->border_green;
2125     ann->annotcolor.value[2] = p->border_blue;
2126     ann->annotcolor.value[3] = 0;
2127     ann->dasharray[0] = p->border_dash1;
2128     ann->dasharray[1] = p->border_dash2;
2129 }
2130 
2131 void
pdf__attach_file(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * filename,int len_filename,const char * description,int len_descr,const char * author,int len_auth,const char * mimetype,const char * icon)2132 pdf__attach_file(
2133     PDF *p,
2134     pdc_scalar llx,
2135     pdc_scalar lly,
2136     pdc_scalar urx,
2137     pdc_scalar ury,
2138     const char *filename,
2139     int len_filename,
2140     const char *description,
2141     int len_descr,
2142     const char *author,
2143     int len_auth,
2144     const char *mimetype,
2145     const char *icon)
2146 {
2147     pdc_file *attfile;
2148     pdf_annot *ann;
2149     pdf_attach_iconnames icontype = icon_attach_pushpin;
2150 
2151     filename = pdf_convert_filename(p, filename, len_filename, "filename",
2152                                     PDC_CONV_WITHBOM);
2153 
2154     if (icon != NULL && *icon)
2155     {
2156         int k = pdc_get_keycode_ci(icon, pdf_attach_iconnames_pdfkeylist);
2157         if (k == PDC_KEY_NOTFOUND)
2158             pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0);
2159         icontype = (pdf_attach_iconnames) k;
2160     }
2161 
2162     attfile = pdc_fsearch_fopen(p->pdc, filename, NULL, "attachment ", 0);
2163     if (attfile == NULL)
2164         pdc_error(p->pdc, -1, 0, 0, 0, 0);
2165 
2166     pdc_lock_pvf(p->pdc, filename);
2167     pdc_fclose(attfile);
2168 
2169     /* fill up annotation struct */
2170     ann = pdf_new_annot(p, ann_fileattachment);
2171     ann->zoom = pdc_false;
2172     ann->rotate = pdc_false;
2173     pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2174     pdf_insert_annot_params(p, ann);
2175     ann->filename = pdc_strdup(p->pdc, filename);
2176     ann->nativefilename = pdc_strdup(p->pdc, filename);
2177     ann->filesize = pdf_check_file(p, ann->filename, pdc_true);
2178     ann->contents = pdf_convert_hypertext_depr(p, description, len_descr);
2179     ann->title = pdf_convert_hypertext_depr(p, author, len_auth);
2180     if (mimetype != NULL && mimetype)
2181         ann->mimetype = pdc_strdup(p->pdc, mimetype);
2182     if (icontype != icon_attach_pushpin)
2183         ann->iconname =
2184             pdc_get_keyword(icontype, pdf_attach_iconnames_pdfkeylist);
2185 }
2186 
2187 void
pdf__add_note(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * contents,int len_cont,const char * title,int len_title,const char * icon,int kopen)2188 pdf__add_note(
2189     PDF *p,
2190     pdc_scalar llx,
2191     pdc_scalar lly,
2192     pdc_scalar urx,
2193     pdc_scalar ury,
2194     const char *contents,
2195     int len_cont,
2196     const char *title,
2197     int len_title,
2198     const char *icon,
2199     int kopen)
2200 {
2201     pdf_annot *ann;
2202     pdf_text_iconnames icontype = icon_text_note;
2203 
2204     if (icon != NULL && *icon)
2205     {
2206         int k = pdc_get_keycode_ci(icon, pdf_text_iconnames_pdfkeylist);
2207         if (k == PDC_KEY_NOTFOUND)
2208             pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0);
2209         icontype = (pdf_text_iconnames) k;
2210     }
2211 
2212     /* fill up annotation struct */
2213     ann = pdf_new_annot(p, ann_text);
2214     pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2215     pdf_insert_annot_params(p, ann);
2216     ann->contents = pdf_convert_hypertext_depr(p, contents, len_cont);
2217     ann->title = pdf_convert_hypertext_depr(p, title, len_title);
2218     if (icontype != icon_text_note)
2219         ann->iconname = pdc_get_keyword(icontype,pdf_text_iconnames_pdfkeylist);
2220     ann->open = kopen;
2221     ann->display = disp_noprint;
2222 }
2223 
2224 void
pdf__add_pdflink(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * filename,int page,const char * optlist)2225 pdf__add_pdflink(
2226     PDF *p,
2227     pdc_scalar llx,
2228     pdc_scalar lly,
2229     pdc_scalar urx,
2230     pdc_scalar ury,
2231     const char *filename,
2232     int page,
2233     const char *optlist)
2234 {
2235     static const char *fn = "pdf__add_pdflink";
2236     char *actoptlist, *sopt;
2237     pdf_annot *ann;
2238     int acthdl;
2239     size_t size;
2240 
2241     if (filename == NULL || *filename == '\0')
2242         pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0);
2243 
2244     if (optlist == NULL)
2245         optlist = "";
2246 
2247     size = strlen(filename) + strlen(optlist) + 80;
2248     actoptlist = (char *) pdc_malloc(p->pdc, size, fn);
2249 
2250     /* creating a GoToR action */
2251     actoptlist[0] = 0;
2252     sopt = actoptlist;
2253     sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "filename {%s} ", filename);
2254     sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "destination {%s page %d} ",
2255                         optlist, page);
2256     acthdl = pdf__create_action(p, "GoToR", actoptlist);
2257 
2258     /* fill up annotation struct */
2259     if (acthdl > -1)
2260     {
2261         ann = pdf_new_annot(p, ann_link);
2262         pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2263         pdf_insert_annot_params(p, ann);
2264         if (p->pdc->hastobepos) acthdl++;
2265         pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl);
2266         ann->action = pdc_strdup(p->pdc, actoptlist);
2267         ann->display = disp_noprint;
2268     }
2269 
2270     pdc_free(p->pdc, actoptlist);
2271 }
2272 
2273 void
pdf__add_launchlink(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * filename)2274 pdf__add_launchlink(
2275     PDF *p,
2276     pdc_scalar llx,
2277     pdc_scalar lly,
2278     pdc_scalar urx,
2279     pdc_scalar ury,
2280     const char *filename)
2281 {
2282     static const char *fn = "pdf__add_launchlink";
2283     char *actoptlist, *sopt;
2284     pdf_annot *ann;
2285     int acthdl;
2286     size_t size;
2287 
2288     if (filename == NULL || *filename == '\0')
2289         pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0);
2290     size = strlen(filename) + 80;
2291     if (p->launchlink_parameters)
2292         size += strlen(p->launchlink_parameters);
2293     if (p->launchlink_operation)
2294         size += strlen(p->launchlink_operation);
2295     if (p->launchlink_defaultdir)
2296         size += strlen(p->launchlink_defaultdir);
2297     actoptlist = (char *) pdc_malloc(p->pdc, size, fn);
2298 
2299     /* creating a Launch action */
2300     actoptlist[0] = 0;
2301     sopt = actoptlist;
2302     sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "filename {%s} ", filename);
2303     if (p->launchlink_parameters)
2304     {
2305         sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "parameters {%s} ",
2306                                           p->launchlink_parameters);
2307         pdc_free(p->pdc, p->launchlink_parameters);
2308         p->launchlink_parameters = NULL;
2309     }
2310     if (p->launchlink_operation)
2311     {
2312         sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "operation {%s} ",
2313                                           p->launchlink_operation);
2314         pdc_free(p->pdc, p->launchlink_operation);
2315         p->launchlink_operation = NULL;
2316     }
2317     if (p->launchlink_defaultdir)
2318     {
2319         sopt += pdc_sprintf(p->pdc, pdc_false, sopt, "defaultdir {%s} ",
2320                                           p->launchlink_defaultdir);
2321         pdc_free(p->pdc, p->launchlink_defaultdir);
2322         p->launchlink_defaultdir = NULL;
2323     }
2324     acthdl = pdf__create_action(p, "Launch", actoptlist);
2325 
2326     /* fill up annotation struct */
2327     if (acthdl > -1)
2328     {
2329         ann = pdf_new_annot(p, ann_link);
2330         pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2331         pdf_insert_annot_params(p, ann);
2332         if (p->pdc->hastobepos) acthdl++;
2333         pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl);
2334         ann->action = pdc_strdup(p->pdc, actoptlist);
2335         ann->display = disp_noprint;
2336     }
2337 
2338     pdc_free(p->pdc, actoptlist);
2339 }
2340 
2341 void
pdf__add_locallink(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,int page,const char * optlist)2342 pdf__add_locallink(
2343     PDF *p,
2344     pdc_scalar llx,
2345     pdc_scalar lly,
2346     pdc_scalar urx,
2347     pdc_scalar ury,
2348     int page,
2349     const char *optlist)
2350 {
2351     pdf_annot *ann;
2352 
2353     /* fill up annotation struct */
2354     ann = pdf_new_annot(p, ann_link);
2355     pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2356     pdf_insert_annot_params(p, ann);
2357     ann->dest = pdf_parse_destination_optlist(p, optlist, page, pdf_locallink);
2358     ann->display = disp_noprint;
2359 }
2360 
2361 void
pdf__add_weblink(PDF * p,pdc_scalar llx,pdc_scalar lly,pdc_scalar urx,pdc_scalar ury,const char * url)2362 pdf__add_weblink(
2363     PDF *p,
2364     pdc_scalar llx,
2365     pdc_scalar lly,
2366     pdc_scalar urx,
2367     pdc_scalar ury,
2368     const char *url)
2369 {
2370     static const char *fn = "pdf__add_weblink";
2371     char *actoptlist;
2372     pdf_annot *ann;
2373     int acthdl;
2374 
2375     if (url == NULL || *url == '\0')
2376         pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "url", 0, 0, 0);
2377     actoptlist = (char *) pdc_malloc(p->pdc, strlen(url) + 80, fn);
2378 
2379     /* creating a URI action */
2380     pdc_sprintf(p->pdc, pdc_false, actoptlist, "url {%s} ", url);
2381     acthdl = pdf__create_action(p, "URI", actoptlist);
2382 
2383     /* fill up annotation struct */
2384     if (acthdl > -1)
2385     {
2386         ann = pdf_new_annot(p, ann_link);
2387         pdf_init_rectangle(p, ann, llx, lly, urx, ury, NULL);
2388         pdf_insert_annot_params(p, ann);
2389         if (p->pdc->hastobepos) acthdl++;
2390         pdc_sprintf(p->pdc, pdc_false, actoptlist, "activate %d", acthdl);
2391         ann->action = pdc_strdup(p->pdc, actoptlist);
2392         ann->display = disp_noprint;
2393     }
2394 
2395     pdc_free(p->pdc, actoptlist);
2396 }
2397 
2398 void
pdf__set_border_style(PDF * p,const char * style,pdc_scalar width)2399 pdf__set_border_style(PDF *p, const char *style, pdc_scalar width)
2400 {
2401     int k;
2402 
2403     p->border_style = border_solid;
2404     if (style)
2405     {
2406         k = pdc_get_keycode_ci(style, pdf_borderstyle_keylist);
2407         if (k == PDC_KEY_NOTFOUND)
2408             pdc_error(p->pdc, PDC_E_ILLARG_STRING, "style", style, 0, 0);
2409         p->border_style = (pdf_borderstyle) k;
2410     }
2411 
2412     pdc_check_number_limits(p->pdc, "width", width, 0.0, PDC_FLOAT_MAX);
2413 
2414     p->border_width = width;
2415 }
2416 
2417 void
pdf__set_border_color(PDF * p,pdc_scalar red,pdc_scalar green,pdc_scalar blue)2418 pdf__set_border_color(PDF *p, pdc_scalar red, pdc_scalar green, pdc_scalar blue)
2419 {
2420     pdc_check_number_limits(p->pdc, "red", red, 0.0, 1.0);
2421     pdc_check_number_limits(p->pdc, "green", green, 0.0, 1.0);
2422     pdc_check_number_limits(p->pdc, "blue", blue, 0.0, 1.0);
2423 
2424     p->border_red = red;
2425     p->border_green = green;
2426     p->border_blue = blue;
2427 }
2428 
2429 void
pdf__set_border_dash(PDF * p,pdc_scalar b,pdc_scalar w)2430 pdf__set_border_dash(PDF *p, pdc_scalar b, pdc_scalar w)
2431 {
2432     pdc_check_number_limits(p->pdc, "b", b, 0.0, PDC_FLOAT_MAX);
2433     pdc_check_number_limits(p->pdc, "w", w, 0.0, PDC_FLOAT_MAX);
2434 
2435     p->border_dash1 = b;
2436     p->border_dash2 = w;
2437 }
2438