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