1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2 
3     Copyright (C) 2002-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4     the dvipdfmx project team.
5 
6     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdarg.h>
28 
29 #include "system.h"
30 #include "mem.h"
31 #include "error.h"
32 #include "numbers.h"
33 
34 #include "dvi.h"
35 
36 #include "pdfobj.h"
37 #include "pdfparse.h"
38 #include "pdfdoc.h"
39 #include "pdfnames.h"
40 
41 #include "pdfdraw.h"
42 #include "pdfdev.h"
43 
44 #include "spc_pdfm.h"
45 #include "spc_tpic.h"
46 #include "spc_html.h"
47 #include "spc_misc.h"
48 #include "spc_color.h"
49 #include "spc_dvips.h"
50 #include "spc_xtx.h"
51 
52 #include "specials.h"
53 
54 static int verbose = 0;
55 void
spc_set_verbose(void)56 spc_set_verbose (void)
57 {
58   verbose++;
59 }
60 
61 
62 void
spc_warn(struct spc_env * spe,const char * fmt,...)63 spc_warn (struct spc_env *spe, const char *fmt, ...)
64 {
65   va_list  ap;
66   static char buf[1024];
67 
68   va_start(ap, fmt);
69 
70   vsprintf(buf, fmt, ap);
71   WARN(buf);
72 
73   va_end(ap);
74 
75   return;
76 }
77 
78 
79 /* This is currently just to make other spc_xxx to not directly
80  * call dvi_xxx.
81  */
82 int
spc_begin_annot(struct spc_env * spe,pdf_obj * dict)83 spc_begin_annot (struct spc_env *spe, pdf_obj *dict)
84 {
85   pdf_doc_begin_annot(dict);
86   dvi_tag_depth(); /* Tell dvi interpreter to handle line-break. */
87   return  0;
88 }
89 
90 int
spc_end_annot(struct spc_env * spe)91 spc_end_annot (struct spc_env *spe)
92 {
93   dvi_untag_depth();
94   pdf_doc_end_annot();
95   return  0;
96 }
97 
98 int
spc_resume_annot(struct spc_env * spe)99 spc_resume_annot (struct spc_env *spe)
100 {
101   dvi_link_annot(1);
102   return  0;
103 }
104 
105 int
spc_suspend_annot(struct spc_env * spe)106 spc_suspend_annot (struct spc_env *spe)
107 {
108   dvi_link_annot(0);
109   return  0;
110 }
111 
112 
113 
114 static struct ht_table *named_objects = NULL;
115 
116 /* reserved keys */
117 static const char *_rkeys[] = {
118 #define  K_OBJ__XPOS      0
119 #define  K_OBJ__YPOS      1
120   "xpos", "ypos",
121 #define  K_OBJ__THISPAGE  2
122 #define  K_OBJ__PREVPAGE  3
123 #define  K_OBJ__NEXTPAGE  4
124   "thispage", "prevpage", "nextpage",
125 #define  K_OBJ__RESOURCES 5
126   "resources",
127 #define  K_OBJ__PAGES     6
128 #define  K_OBJ__NAMES     7
129   "pages", "names",
130 #define  K_OBJ__CATALOG   8
131 #define  K_OBJ__DOCINFO   9
132   "catalog", "docinfo",
133 #if  0
134 #define  K_OBJ__TRAILER  10
135   "trailer",
136 #endif /* NYI */
137   NULL
138 };
139 
140 /* pageN where N is a positive integer.
141  * Note that page need not exist at this time.
142  */
143 static int
ispageref(const char * key)144 ispageref (const char *key)
145 {
146   const char  *p;
147   if (strlen(key) <= strlen("page") ||
148       memcmp(key, "page", strlen("page")))
149     return  0;
150   else {
151     for (p = key + 4; *p && *p >= '0' && *p <= '9'; p++);
152     if (*p != '\0')
153       return  0;
154   }
155   return  1;
156 }
157 
158 /*
159  * The following routine returns copies, not the original object.
160  */
161 pdf_obj *
spc_lookup_reference(const char * key)162 spc_lookup_reference (const char *key)
163 {
164   pdf_obj    *value = NULL;
165   pdf_coord   cp;
166   int         k;
167 
168   ASSERT(named_objects);
169 
170   if (!key)
171     return  NULL;
172 
173   for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++);
174   switch (k) {
175   /* xpos and ypos must be position in device space here. */
176   case  K_OBJ__XPOS:
177     cp.x = dvi_dev_xpos(); cp.y = 0.0;
178     pdf_dev_transform(&cp, NULL);
179     value = pdf_new_number(ROUND(cp.x, .01));
180     break;
181   case  K_OBJ__YPOS:
182     cp.x = 0.0; cp.y = dvi_dev_ypos();
183     pdf_dev_transform(&cp, NULL);
184     value = pdf_new_number(ROUND(cp.y, .01));
185     break;
186   case  K_OBJ__THISPAGE:
187     value = pdf_doc_this_page_ref();
188     break;
189   case  K_OBJ__PREVPAGE:
190     value = pdf_doc_prev_page_ref();
191     break;
192   case  K_OBJ__NEXTPAGE:
193     value = pdf_doc_next_page_ref();
194     break;
195   case  K_OBJ__PAGES:
196     value = pdf_ref_obj(pdf_doc_page_tree());
197     break;
198   case  K_OBJ__NAMES:
199     value = pdf_ref_obj(pdf_doc_names());
200     break;
201   case  K_OBJ__RESOURCES:
202     value = pdf_ref_obj(pdf_doc_current_page_resources());
203     break;
204   case  K_OBJ__CATALOG:
205     value = pdf_ref_obj(pdf_doc_catalog());
206     break;
207   case  K_OBJ__DOCINFO:
208     value = pdf_ref_obj(pdf_doc_docinfo());
209     break;
210   default:
211     if (ispageref(key))
212       value = pdf_doc_ref_page(atoi(key + 4));
213     else {
214       value = pdf_names_lookup_reference(named_objects, key, strlen(key));
215     }
216     break;
217   }
218 
219   if (!value) {
220     ERROR("Object reference %s not exist.", key);
221   }
222 
223   return  value;
224 }
225 
226 pdf_obj *
spc_lookup_object(const char * key)227 spc_lookup_object (const char *key)
228 {
229   pdf_obj    *value = NULL;
230   pdf_coord   cp;
231   int         k;
232 
233   ASSERT(named_objects);
234 
235   if (!key)
236     return  NULL;
237 
238   for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++);
239   switch (k) {
240   case  K_OBJ__XPOS:
241     cp.x = dvi_dev_xpos(); cp.y = 0.0;
242     pdf_dev_transform(&cp, NULL);
243     value = pdf_new_number(ROUND(cp.x, .01));
244     break;
245   case  K_OBJ__YPOS:
246     cp.x = 0.0; cp.y = dvi_dev_ypos();
247     pdf_dev_transform(&cp, NULL);
248     value = pdf_new_number(ROUND(cp.y, .01));
249     break;
250   case  K_OBJ__THISPAGE:
251     value = pdf_doc_this_page();
252     break;
253   case  K_OBJ__PAGES:
254     value = pdf_doc_page_tree();
255     break;
256   case  K_OBJ__NAMES:
257     value = pdf_doc_names();
258     break;
259   case  K_OBJ__RESOURCES:
260     value = pdf_doc_current_page_resources();
261     break;
262   case  K_OBJ__CATALOG:
263     value = pdf_doc_catalog();
264     break;
265   case  K_OBJ__DOCINFO:
266     value = pdf_doc_docinfo();
267     break;
268   default:
269     value = pdf_names_lookup_object(named_objects, key, strlen(key));
270     break;
271   }
272 
273 /* spc_handler_pdfm_bead() in spc_pdfm.c controls NULL too.
274   if (!value) {
275     ERROR("Object reference %s not exist.", key);
276   }
277 */
278 
279   return  value;
280 }
281 
282 void
spc_push_object(const char * key,pdf_obj * value)283 spc_push_object (const char *key, pdf_obj *value)
284 {
285   ASSERT(named_objects);
286 
287   if (!key || !value)
288     return;
289 
290   pdf_names_add_object(named_objects, key, strlen(key), value);
291 }
292 
293 void
spc_flush_object(const char * key)294 spc_flush_object (const char *key)
295 {
296   pdf_names_close_object(named_objects, key, strlen(key));
297 }
298 
299 void
spc_clear_objects(void)300 spc_clear_objects (void)
301 {
302   pdf_delete_name_tree(&named_objects);
303   named_objects = pdf_new_name_tree();
304 }
305 
306 
307 static int
spc_handler_unknown(struct spc_env * spe,struct spc_arg * args)308 spc_handler_unknown (struct spc_env *spe,
309                      struct spc_arg *args)
310 {
311   ASSERT(spe && args);
312 
313   args->curptr = args->endptr;
314 
315   return  -1;
316 }
317 
318 static void
init_special(struct spc_handler * special,struct spc_env * spe,struct spc_arg * args,const char * p,uint32_t size,double x_user,double y_user,double mag)319 init_special (struct spc_handler *special,
320 	      struct spc_env *spe,
321 	      struct spc_arg *args,
322 	      const char *p, uint32_t size,
323 	      double x_user, double y_user, double mag)
324 {
325 
326   special->key  = NULL;
327   special->exec = (spc_handler_fn_ptr) &spc_handler_unknown;
328 
329   spe->x_user = x_user;
330   spe->y_user = y_user;
331   spe->mag    = mag;
332   spe->pg     = pdf_doc_current_page_number(); /* _FIXME_ */
333 
334   args->curptr = p;
335   args->endptr = args->curptr + size;
336   args->base   = args->curptr;
337   args->command = NULL;
338 
339   return;
340 }
341 
342 static void
check_garbage(struct spc_arg * args)343 check_garbage (struct spc_arg *args)
344 {
345   ASSERT(args);
346 
347   if (args->curptr >= args->endptr)
348     return;
349 
350   skip_white(&args->curptr, args->endptr);
351   if (args->curptr < args->endptr) {
352     WARN("Unparsed material at end of special ignored.");
353     dump(args->curptr, args->endptr);
354   }
355 
356   return;
357 }
358 
359 static struct {
360   const char  *key;
361   int (*bodhk_func) (void);
362   int (*eodhk_func) (void);
363   int (*bophk_func) (void);
364   int (*eophk_func) (void);
365   int (*check_func) (const char *, long);
366   int (*setup_func) (struct spc_handler *, struct spc_env *, struct spc_arg *);
367 } known_specials[] = {
368 
369   {"pdf:",
370    spc_pdfm_at_begin_document,
371    spc_pdfm_at_end_document,
372    NULL,
373    NULL,
374    spc_pdfm_check_special,
375    spc_pdfm_setup_handler
376   },
377 
378   {"x:",
379    NULL,
380    NULL,
381    NULL,
382    NULL,
383    spc_xtx_check_special,
384    spc_xtx_setup_handler
385   },
386 
387   {"ps:",
388    spc_dvips_at_begin_document,
389    spc_dvips_at_end_document,
390    spc_dvips_at_begin_page,
391    spc_dvips_at_end_page,
392    spc_dvips_check_special,
393    spc_dvips_setup_handler
394   },
395 
396   {"color",
397    NULL,
398    NULL,
399    NULL,
400    NULL,
401    spc_color_check_special,
402    spc_color_setup_handler
403   },
404 
405   {"tpic",
406    spc_tpic_at_begin_document,
407    spc_tpic_at_end_document,
408    spc_tpic_at_begin_page,
409    spc_tpic_at_end_page,
410    spc_tpic_check_special,
411    spc_tpic_setup_handler
412   },
413 
414   {"html:",
415    spc_html_at_begin_document,
416    spc_html_at_end_document,
417    spc_html_at_begin_page,
418    spc_html_at_end_page,
419    spc_html_check_special,
420    spc_html_setup_handler
421   },
422 
423   {"unknown",
424    NULL,
425    NULL,
426    NULL,
427    NULL,
428    spc_misc_check_special,
429    spc_misc_setup_handler
430   },
431 
432   {NULL} /* end */
433 };
434 
435 int
spc_exec_at_begin_page(void)436 spc_exec_at_begin_page (void)
437 {
438   int  error = 0;
439   int  i;
440 
441   for (i = 0; known_specials[i].key != NULL; i++) {
442     if (known_specials[i].bophk_func) {
443       error = known_specials[i].bophk_func();
444     }
445   }
446 
447   return error;
448 }
449 
450 int
spc_exec_at_end_page(void)451 spc_exec_at_end_page (void)
452 {
453   int  error = 0;
454   int  i;
455 
456   for (i = 0; known_specials[i].key != NULL; i++) {
457     if (known_specials[i].eophk_func) {
458       error = known_specials[i].eophk_func();
459     }
460   }
461 
462   return error;
463 }
464 
465 int
spc_exec_at_begin_document(void)466 spc_exec_at_begin_document (void)
467 {
468   int  error = 0;
469   int  i;
470 
471   ASSERT(!named_objects);
472 
473   named_objects = pdf_new_name_tree();
474 
475   for (i = 0; known_specials[i].key != NULL; i++) {
476     if (known_specials[i].bodhk_func) {
477       error = known_specials[i].bodhk_func();
478     }
479   }
480 
481   return error;
482 }
483 
484 int
spc_exec_at_end_document(void)485 spc_exec_at_end_document (void)
486 {
487   int  error = 0;
488   int  i;
489 
490   for (i = 0; known_specials[i].key != NULL; i++) {
491     if (known_specials[i].eodhk_func) {
492       error = known_specials[i].eodhk_func();
493     }
494   }
495 
496   if (named_objects) {
497     pdf_delete_name_tree(&named_objects);
498   }
499 
500   return error;
501 }
502 
503 static void
print_error(const char * name,struct spc_env * spe,struct spc_arg * ap)504 print_error (const char *name, struct spc_env *spe, struct spc_arg *ap)
505 {
506   const char *p;
507   char      ebuf[64];
508   int       i;
509   long      pg = spe->pg;
510   pdf_coord c;
511 
512   c.x = spe->x_user; c.y = spe->y_user;
513   pdf_dev_transform(&c, NULL);
514 
515   if (ap->command && name) {
516     WARN("Interpreting special command %s (%s) failed.", ap->command, name);
517     WARN(">> at page=\"%ld\" position=\"(%g, %g)\" (in PDF)", pg, c.x, c.y);
518   }
519   for (i = 0, p = ap->base; i < 63 && p < ap->endptr; p++) {
520     if (isprint((unsigned char)*p))
521       ebuf[i++] = *p;
522     else if (i + 4 < 63)
523       i += sprintf(ebuf + i, "\\x%02x", (unsigned char)*p);
524     else
525       break;
526   }
527   ebuf[i] = '\0';
528   if (ap->curptr < ap->endptr) {
529     while (i-- > 60)
530       ebuf[i] = '.';
531   }
532   WARN(">> xxx \"%s\"", ebuf);
533 
534   if (ap->curptr < ap->endptr) {
535     for (i = 0, p = ap->curptr; i < 63 && p < ap->endptr; p++) {
536       if (isprint((unsigned char)*p))
537         ebuf[i++] = *p;
538       else if (i + 4 < 63)
539         i += sprintf(ebuf + i, "\\x%02x", (unsigned char)*p);
540       else
541         break;
542     }
543     ebuf[i] = '\0';
544     if (ap->curptr < ap->endptr) {
545       while (i-- > 60)
546         ebuf[i] = '.';
547     }
548     WARN(">> Reading special command stopped around >>%s<<", ebuf);
549 
550     ap->curptr = ap->endptr;
551   }
552 }
553 
554 int
spc_exec_special(const char * buffer,int32_t size,double x_user,double y_user,double mag)555 spc_exec_special (const char *buffer, int32_t size,
556 		  double x_user, double y_user, double mag)
557 {
558   int    error = -1;
559   int    i, found;
560   struct spc_env     spe;
561   struct spc_arg     args;
562   struct spc_handler special;
563 
564   if (verbose > 3) {
565     dump(buffer, buffer + size);
566   }
567 
568   init_special(&special, &spe, &args, buffer, size, x_user, y_user, mag);
569 
570   for (i = 0; known_specials[i].key != NULL; i++) {
571     found = known_specials[i].check_func(buffer, size);
572     if (found) {
573       error = known_specials[i].setup_func(&special, &spe, &args);
574       if (!error) {
575 	error = special.exec(&spe, &args);
576       }
577       if (error) {
578 	print_error(known_specials[i].key, &spe, &args);
579       }
580       break;
581     }
582   }
583 
584   check_garbage(&args);
585 
586   return error;
587 }
588 
589