1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2 
3     Copyright (C) 2007-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 <ctype.h>
28 #include <string.h>
29 #include <math.h>
30 
31 #include "system.h"
32 #include "mem.h"
33 #include "error.h"
34 #include "mfileio.h"
35 #include "numbers.h"
36 
37 #include "tfm.h"
38 
39 #include "pdfobj.h"
40 #include "pdfparse.h"
41 #include "pdfdev.h"
42 #include "pdfdoc.h"
43 
44 #include "pdfcolor.h"
45 #include "pdfdraw.h"
46 
47 #include "fontmap.h"
48 #include "subfont.h"
49 
50 #include "pdfximage.h"
51 
52 #include "mpost.h"
53 
54 /*
55  * Define the origin as (llx, lly) in order to
56  * match the new xetex.def and dvipdfmx.def
57  */
58 
59 static double Xorigin, Yorigin;
60 
61 /*
62  * In PDF, current path is not a part of graphics state parameter.
63  * Hence, current path is not saved by the "q" operator  and is not
64  * recovered by the "Q" operator. This means that the following PS
65  * code
66  *
67  *   <path construction> gsave <path painting> grestore ...
68  *
69  * can't be translated to PDF code
70  *
71  *   <path construction> q <path painting> Q ...
72  *
73  * . Only clipping path (which is graphics state parameter in PDF
74  * too) is treated in the same way. So, we write clipping path
75  * immediately and forget about it but remember current path.
76  */
77 
78 static int mp_parse_body (const char **start, const char *end, double x_user, double y_user);
79 
80 static struct mp_font
81 {
82   char   *font_name;
83   int     font_id;
84   int     tfm_id;     /* Used for text width calculation */
85   int     subfont_id;
86   double  pt_size;
87 } font_stack[PDF_GSAVE_MAX] = {
88   {NULL, -1, -1, -1, 0}
89 };
90 static int currentfont = -1;
91 
92 #define CURRENT_FONT() ((currentfont < 0) ? NULL : &font_stack[currentfont])
93 
94 /* Compatibility */
95 #define MP_CMODE_MPOST    0
96 #define MP_CMODE_DVIPSK   1
97 #define MP_CMODE_PTEXVERT 2
98 static int mp_cmode = MP_CMODE_MPOST;
99 
100 static int
mp_setfont(const char * font_name,double pt_size)101 mp_setfont (const char *font_name, double pt_size)
102 {
103   const char     *name = font_name;
104   struct mp_font *font;
105   int             subfont_id = -1;
106   fontmap_rec    *mrec;
107 
108   font = CURRENT_FONT();
109 
110   if (font) {
111     if (!strcmp(font->font_name, font_name) &&
112         font->pt_size == pt_size)
113       return  0;
114   } else { /* No currentfont */
115 /* ***TODO*** Here some problem exists! */
116     font = &font_stack[0];
117     font->font_name = NULL;
118     currentfont = 0;
119   }
120 
121   mrec = pdf_lookup_fontmap_record(font_name);
122   if (mrec && mrec->charmap.sfd_name && mrec->charmap.subfont_id) {
123     subfont_id = sfd_load_record(mrec->charmap.sfd_name, mrec->charmap.subfont_id);
124   }
125 
126   /* See comments in dvi_locate_font() in dvi.c. */
127   if (mrec && mrec->map_name) {
128     name = mrec->map_name;
129   } else {
130     name = font_name;
131   }
132 
133   if (font->font_name)
134     RELEASE(font->font_name);
135   font->font_name  = NEW(strlen(font_name) + 1, char);
136   strcpy(font->font_name, font_name);
137   font->subfont_id = subfont_id;
138   font->pt_size    = pt_size;
139   font->tfm_id     = tfm_open(font_name, 0); /* Need not exist in MP mode */
140   font->font_id    = pdf_dev_locate_font(name,
141                                          (spt_t) (pt_size * dev_unit_dviunit()));
142 
143   if (font->font_id < 0) {
144     ERROR("MPOST: No physical font assigned for \"%s\".", font_name);
145     return 1;
146   }
147 
148   return  0;
149 }
150 
151 static void
save_font(void)152 save_font (void)
153 {
154   struct mp_font *current, *next;
155 
156   if (currentfont < 0) {
157     font_stack[0].font_name  = NEW(strlen("Courier") + 1, char);
158     strcpy(font_stack[0].font_name, "Courier");
159     font_stack[0].pt_size    = 1;
160     font_stack[0].tfm_id     = 0;
161     font_stack[0].subfont_id = 0;
162     currentfont = 0;
163   }
164 
165   current = &font_stack[currentfont++];
166   next    = &font_stack[currentfont  ];
167   next->font_name  = NEW(strlen(current->font_name)+1, char);
168   strcpy(next->font_name, current->font_name);
169   next->pt_size    = current->pt_size;
170 
171   next->subfont_id = current->subfont_id;
172   next->tfm_id     = current->tfm_id;
173 }
174 
175 static void
restore_font(void)176 restore_font (void)
177 {
178   struct mp_font *current;
179 
180   current = CURRENT_FONT();
181   if (current) {
182     if (current->font_name)
183       RELEASE(current->font_name);
184     current->font_name = NULL;
185   } else {
186     ERROR("No currentfont...");
187   }
188 
189   currentfont--;
190 }
191 
192 static void
clear_fonts(void)193 clear_fonts (void)
194 {
195   while (currentfont >= 0) {
196     if (font_stack[currentfont].font_name)
197       RELEASE(font_stack[currentfont].font_name);
198     currentfont--;
199   }
200 }
201 
202 static int
is_fontname(const char * token)203 is_fontname (const char *token)
204 {
205   fontmap_rec *mrec;
206 
207   mrec = pdf_lookup_fontmap_record(token);
208   if (mrec)
209     return  1;
210 
211   return  tfm_exists(token);
212 }
213 
214 int
mps_scan_bbox(const char ** pp,const char * endptr,pdf_rect * bbox)215 mps_scan_bbox (const char **pp, const char *endptr, pdf_rect *bbox)
216 {
217   char  *number;
218   double values[4];
219   int    i;
220 
221   /* skip_white() skips lines starting '%'... */
222   while (*pp < endptr && isspace((unsigned char)**pp))
223     (*pp)++;
224 
225   /* Scan for bounding box record */
226   while (*pp < endptr && **pp == '%') {
227     if (*pp + 14 < endptr &&
228 	!strncmp(*pp, "%%BoundingBox:", 14)) {
229 
230       *pp += 14;
231 
232       for (i = 0; i < 4; i++) {
233 	skip_white(pp, endptr);
234 	number = parse_number(pp, endptr);
235 	if (!number) {
236 	  break;
237 	}
238 	values[i] = atof(number);
239 	RELEASE(number);
240       }
241       if (i < 4) {
242 	return -1;
243       } else {
244 	/* The new xetex.def and dvipdfmx.def require bbox->llx = bbox->lly = 0.  */
245 	bbox->llx = 0;
246 	bbox->lly = 0;
247 	bbox->urx = values[2] - values[0];
248 	bbox->ury = values[3] - values[1];
249 
250 	Xorigin = (double)values[0];
251 	Yorigin = (double)values[1];
252 
253 	return 0;
254       }
255     }
256     skip_line (pp, endptr);
257     while (*pp < endptr && isspace((unsigned char)**pp))
258       (*pp)++;
259   }
260 
261   return -1;
262 }
263 
264 static void
skip_prolog(const char ** start,const char * end)265 skip_prolog (const char **start, const char *end)
266 {
267   int   found_prolog = 0;
268   const char *save;
269 
270   save = *start;
271   while (*start < end) {
272     if (**start != '%')
273       skip_white(start, end);
274     if (*start >= end)
275       break;
276     if (!strncmp(*start, "%%EndProlog", 11)) {
277       found_prolog = 1;
278       skip_line(start, end);
279       break;
280     } else if (!strncmp(*start, "%%Page:", 7)) {
281       skip_line(start, end);
282       break;
283     }
284     skip_line(start, end);
285   }
286   if (!found_prolog) {
287     *start = save;
288   }
289 
290   return;
291 }
292 
293 /* PostScript Operators */
294 
295 #define ADD          	1
296 #define SUB		2
297 #define MUL		3
298 #define DIV		4
299 #define NEG    	        5
300 #define TRUNCATE	6
301 
302 #define CLEAR		10
303 #define EXCH		11
304 #define POP		12
305 
306 #define NEWPATH		31
307 #define CLOSEPATH    	32
308 #define MOVETO		33
309 #define RMOVETO         34
310 #define CURVETO   	35
311 #define RCURVETO        36
312 #define LINETO		37
313 #define RLINETO		38
314 #define ARC             39
315 #define ARCN            40
316 
317 #define FILL		41
318 #define STROKE		42
319 #define SHOW		43
320 
321 #define CLIP         	44
322 #define EOCLIP         	45
323 
324 #define SHOWPAGE	49
325 
326 #define GSAVE		50
327 #define GRESTORE	51
328 
329 #define CONCAT       	52
330 #define SCALE		53
331 #define TRANSLATE	54
332 #define ROTATE          55
333 
334 #define SETLINEWIDTH	60
335 #define SETDASH		61
336 #define SETLINECAP 	62
337 #define SETLINEJOIN	63
338 #define SETMITERLIMIT	64
339 
340 #define SETGRAY		70
341 #define SETRGBCOLOR	71
342 #define SETCMYKCOLOR	72
343 
344 #define CURRENTPOINT    80
345 #define IDTRANSFORM	81
346 #define DTRANSFORM	82
347 
348 #define FINDFONT        201
349 #define SCALEFONT       202
350 #define SETFONT         203
351 #define CURRENTFONT     204
352 
353 #define STRINGWIDTH     210
354 
355 #define DEF             999
356 
357 #define FSHOW		1001
358 #define STEXFIG         1002
359 #define ETEXFIG         1003
360 #define HLW             1004
361 #define VLW             1005
362 #define RD              1006
363 #define B               1007
364 
365 static struct operators
366 {
367   const char *token;
368   int         opcode;
369 } ps_operators[] = {
370   {"add",          ADD},
371   {"mul",          MUL},
372   {"div",          DIV},
373   {"neg",          NEG},
374   {"sub",          SUB},
375   {"truncate",     TRUNCATE},
376 
377   {"clear",        CLEAR},
378   {"exch",         EXCH},
379   {"pop",          POP},
380 
381   {"clip",         CLIP},
382   {"eoclip",       EOCLIP},
383   {"closepath",    CLOSEPATH},
384   {"concat",       CONCAT},
385 
386   {"newpath",      NEWPATH},
387   {"moveto",       MOVETO},
388   {"rmoveto",      RMOVETO},
389   {"lineto",       LINETO},
390   {"rlineto",      RLINETO},
391   {"curveto",      CURVETO},
392   {"rcurveto",     RCURVETO},
393   {"arc",          ARC},
394   {"arcn",         ARCN},
395 
396   {"stroke",       STROKE},
397   {"fill",         FILL},
398   {"show",         SHOW},
399   {"showpage",     SHOWPAGE},
400 
401   {"gsave",        GSAVE},
402   {"grestore",     GRESTORE},
403   {"translate",    TRANSLATE},
404   {"rotate",       ROTATE},
405   {"scale",        SCALE},
406 
407   {"setlinecap",    SETLINECAP},
408   {"setlinejoin",   SETLINEJOIN},
409   {"setlinewidth",  SETLINEWIDTH},
410   {"setmiterlimit", SETMITERLIMIT},
411   {"setdash",       SETDASH},
412 
413   {"setgray",      SETGRAY},
414   {"setrgbcolor",  SETRGBCOLOR},
415   {"setcmykcolor", SETCMYKCOLOR},
416 
417   {"currentpoint", CURRENTPOINT}, /* This is here for rotate support
418 				     in graphics package-not MP support */
419   {"dtransform",   DTRANSFORM},
420   {"idtransform",  IDTRANSFORM},
421 
422   {"findfont",     FINDFONT},
423   {"scalefont",    SCALEFONT},
424   {"setfont",      SETFONT},
425   {"currentfont",  CURRENTFONT},
426 
427   {"stringwidth",  STRINGWIDTH},
428 
429   {"def", DEF} /* not implemented yet; just work with mptopdf */
430 };
431 
432 static struct operators mps_operators[] = {
433   {"fshow",       FSHOW}, /* exch findfont exch scalefont setfont show */
434   {"startTexFig", STEXFIG},
435   {"endTexFig",   ETEXFIG},
436   {"hlw",         HLW}, /* 0 dtransform exch truncate exch idtransform pop setlinewidth */
437   {"vlw",         VLW}, /* 0 exch dtransform truncate idtransform pop setlinewidth pop */
438   {"l",           LINETO},
439   {"r",           RLINETO},
440   {"c",           CURVETO},
441   {"m",           MOVETO},
442   {"p",           CLOSEPATH},
443   {"n",           NEWPATH},
444   {"C",           SETCMYKCOLOR},
445   {"G",           SETGRAY},
446   {"R",           SETRGBCOLOR},
447   {"lj",          SETLINEJOIN},
448   {"ml",          SETMITERLIMIT},
449   {"lc",          SETLINECAP},
450   {"S",           STROKE},
451   {"F",           FILL},
452   {"q",           GSAVE},
453   {"Q",           GRESTORE},
454   {"s",           SCALE},
455   {"t",           CONCAT},
456   {"sd",          SETDASH},
457   {"rd",          RD}, /* [] 0 setdash */
458   {"P",           SHOWPAGE},
459   {"B",           B}, /* gsave fill grestore */
460   {"W",           CLIP}
461 };
462 
463 #define NUM_PS_OPERATORS  (sizeof(ps_operators)/sizeof(ps_operators[0]))
464 #define NUM_MPS_OPERATORS (sizeof(mps_operators)/sizeof(mps_operators[0]))
465 static int
get_opcode(const char * token)466 get_opcode (const char *token)
467 {
468   int   i;
469 
470   for (i = 0; i < NUM_PS_OPERATORS; i++) {
471     if (!strcmp(token, ps_operators[i].token)) {
472       return ps_operators[i].opcode;
473     }
474   }
475 
476   for (i = 0; i < NUM_MPS_OPERATORS; i++) {
477     if (!strcmp(token, mps_operators[i].token)) {
478       return mps_operators[i].opcode;
479     }
480   }
481 
482   return -1;
483 }
484 
485 #define PS_STACK_SIZE 1024
486 
487 static pdf_obj *stack[PS_STACK_SIZE];
488 static unsigned top_stack = 0;
489 
490 #define POP_STACK()     ((top_stack > 0) ? stack[--top_stack] : NULL)
491 #define PUSH_STACK(o,e) { \
492   if (top_stack < PS_STACK_SIZE) { \
493     stack[top_stack++] = (o); \
494   } else { \
495     WARN("PS stack overflow including MetaPost file or inline PS code"); \
496     *(e) = 1; \
497   } \
498 }
499 
500 static int
do_exch(void)501 do_exch (void)
502 {
503   pdf_obj *tmp;
504 
505   if (top_stack < 2)
506     return -1;
507 
508   tmp = stack[top_stack-1];
509   stack[top_stack-1] = stack[top_stack-2];
510   stack[top_stack-2] = tmp;
511 
512   return 0;
513 }
514 
515 static int
do_clear(void)516 do_clear (void)
517 {
518   pdf_obj *tmp;
519 
520   while (top_stack > 0) {
521     tmp = POP_STACK();
522     if (tmp)
523       pdf_release_obj(tmp);
524   }
525 
526   return 0;
527 }
528 
529 /* This should be set_bottom and clear (or
530  * have independent stack) to ensure stack
531  * depth do not go below real stack bottom.
532  */
533 static void
mps_stack_clear_to(int depth)534 mps_stack_clear_to (int depth)
535 {
536   pdf_obj *tmp;
537 
538   while (top_stack > depth) {
539     tmp = POP_STACK();
540     if (tmp)
541       pdf_release_obj(tmp);
542   }
543 
544   return;
545 }
546 
547 static int
pop_get_numbers(double * values,int count)548 pop_get_numbers (double *values, int count)
549 {
550   pdf_obj *tmp;
551 
552   while (count-- > 0) {
553     tmp = POP_STACK();
554     if (!tmp) {
555       WARN("mpost: Stack underflow.");
556       break;
557     } else if (!PDF_OBJ_NUMBERTYPE(tmp)) {
558       WARN("mpost: Not a number!");
559       pdf_release_obj(tmp);
560       break;
561     }
562     values[count] = pdf_number_value(tmp);
563     pdf_release_obj(tmp);
564   }
565 
566   return (count + 1);
567 }
568 
569 static int
cvr_array(pdf_obj * array,double * values,int count)570 cvr_array (pdf_obj *array, double *values, int count)
571 {
572   if (!PDF_OBJ_ARRAYTYPE(array)) {
573     WARN("mpost: Not an array!");
574   } else {
575     pdf_obj *tmp;
576 
577     while (count-- > 0) {
578       tmp = pdf_get_array(array, count);
579       if (!PDF_OBJ_NUMBERTYPE(tmp)) {
580 	WARN("mpost: Not a number!");
581 	break;
582       }
583       values[count] = pdf_number_value(tmp);
584     }
585   }
586   if (array)
587     pdf_release_obj(array);
588 
589   return (count + 1);
590 }
591 
592 static int
is_fontdict(pdf_obj * dict)593 is_fontdict (pdf_obj *dict)
594 {
595   pdf_obj *tmp;
596 
597   if (!PDF_OBJ_DICTTYPE(dict))
598     return 0;
599 
600   tmp = pdf_lookup_dict(dict, "Type");
601   if (!tmp || !PDF_OBJ_NAMETYPE(tmp) ||
602       strcmp(pdf_name_value(tmp), "Font")) {
603     return 0;
604   }
605 
606   tmp = pdf_lookup_dict(dict, "FontName");
607   if (!tmp || !PDF_OBJ_NAMETYPE(tmp)) {
608     return 0;
609   }
610 
611   tmp = pdf_lookup_dict(dict, "FontScale");
612   if (!tmp || !PDF_OBJ_NUMBERTYPE(tmp)) {
613     return 0;
614   }
615 
616   return 1;
617 }
618 
619 static int
do_findfont(void)620 do_findfont (void)
621 {
622   int error = 0;
623   pdf_obj *font_dict, *font_name;
624 
625   font_name = POP_STACK();
626   if (!font_name)
627     return 1;
628   else if (PDF_OBJ_STRINGTYPE(font_name) ||
629 	   PDF_OBJ_NAMETYPE(font_name)) {
630     /* Do not check the existence...
631      * The reason for this is that we cannot locate PK font without
632      * font scale.
633      */
634     font_dict = pdf_new_dict();
635     pdf_add_dict(font_dict,
636 		 pdf_new_name("Type"), pdf_new_name("Font"));
637     if (PDF_OBJ_STRINGTYPE(font_name)) {
638       pdf_add_dict(font_dict,
639 		   pdf_new_name("FontName"),
640 		   pdf_new_name(pdf_string_value(font_name)));
641       pdf_release_obj(font_name);
642     } else {
643       pdf_add_dict(font_dict,
644 		   pdf_new_name("FontName"), font_name);
645     }
646     pdf_add_dict(font_dict,
647 		 pdf_new_name("FontScale"), pdf_new_number(1.0));
648 
649     if (top_stack < PS_STACK_SIZE) {
650       stack[top_stack++] = font_dict;
651     } else {
652       WARN("PS stack overflow including MetaPost file or inline PS code");
653       pdf_release_obj(font_dict);
654       error = 1;
655     }
656   } else {
657     error = 1;
658   }
659 
660   return error;
661 }
662 
663 static int
do_scalefont(void)664 do_scalefont (void)
665 {
666   int error = 0;
667   pdf_obj *font_dict;
668   pdf_obj *font_scale;
669   double   scale;
670 
671   error = pop_get_numbers(&scale, 1);
672   if (error)
673     return error;
674 
675   font_dict = POP_STACK();
676   if (!font_dict)
677     error = 1;
678   else if (is_fontdict(font_dict)) {
679     font_scale  = pdf_lookup_dict(font_dict, "FontScale");
680     pdf_set_number(font_scale, pdf_number_value(font_scale)*scale);
681     if (top_stack < PS_STACK_SIZE) {
682       stack[top_stack++] = font_dict;
683     } else {
684       WARN("PS stack overflow including MetaPost file or inline PS code");
685       pdf_release_obj(font_dict);
686       error = 1;
687     }
688   } else {
689     error = 1;
690   }
691 
692   return error;
693 }
694 
695 static int
do_setfont(void)696 do_setfont (void)
697 {
698   int      error = 0;
699   char    *font_name;
700   double   font_scale;
701   pdf_obj *font_dict;
702 
703   font_dict = POP_STACK();
704   if (!is_fontdict(font_dict))
705     error = 1;
706   else {
707     /* Subfont support prevent us from managing
708      * font in a single place...
709      */
710     font_name  = pdf_name_value  (pdf_lookup_dict(font_dict, "FontName"));
711     font_scale = pdf_number_value(pdf_lookup_dict(font_dict, "FontScale"));
712 
713     error = mp_setfont(font_name, font_scale);
714   }
715   pdf_release_obj(font_dict);
716 
717   return error;
718 }
719 
720 /* Push dummy font dict onto PS stack */
721 static int
do_currentfont(void)722 do_currentfont (void)
723 {
724   int             error = 0;
725   struct mp_font *font;
726   pdf_obj        *font_dict;
727 
728   font = CURRENT_FONT();
729   if (!font) {
730     WARN("Currentfont undefined...");
731     return 1;
732   } else {
733     font_dict = pdf_new_dict();
734     pdf_add_dict(font_dict,
735 		 pdf_new_name("Type"),
736 		 pdf_new_name("Font"));
737     pdf_add_dict(font_dict,
738 		 pdf_new_name("FontName"),
739 		 pdf_new_name(font->font_name));
740     pdf_add_dict(font_dict,
741 		 pdf_new_name("FontScale"),
742 		 pdf_new_number(font->pt_size));
743     if (top_stack < PS_STACK_SIZE) {
744       stack[top_stack++] = font_dict;
745     } else {
746       WARN("PS stack overflow...");
747       pdf_release_obj(font_dict);
748       error = 1;
749     }
750   }
751 
752   return error;
753 }
754 
755 static int
do_show(void)756 do_show (void)
757 {
758   struct mp_font *font;
759   pdf_coord       cp;
760   pdf_obj        *text_str;
761   int             length;
762   unsigned char  *strptr;
763   double          text_width;
764 
765   font = CURRENT_FONT();
766   if (!font) {
767     WARN("Currentfont not set."); /* Should not be error... */
768     return 1;
769   }
770 
771   pdf_dev_currentpoint(&cp);
772 
773   text_str = POP_STACK();
774   if (!PDF_OBJ_STRINGTYPE(text_str)) {
775     if (text_str)
776       pdf_release_obj(text_str);
777     return 1;
778   }
779   if (font->font_id < 0) {
780     WARN("mpost: not set."); /* Should not be error... */
781     pdf_release_obj(text_str);
782     return 1;
783   }
784 
785   strptr = pdf_string_value (text_str);
786   length = pdf_string_length(text_str);
787 
788   if (font->tfm_id < 0) {
789     WARN("mpost: TFM not found for \"%s\".", font->font_name);
790     WARN("mpost: Text width not calculated...");
791   }
792 
793   text_width = 0.0;
794   if (font->subfont_id >= 0) {
795     unsigned short  uch;
796     unsigned char  *ustr;
797     int      i;
798 
799     ustr = NEW(length * 2, unsigned char);
800     for (i = 0; i < length; i++) {
801       uch = lookup_sfd_record(font->subfont_id, strptr[i]);
802       ustr[2*i  ] = uch >> 8;
803       ustr[2*i+1] = uch & 0xff;
804       if (font->tfm_id >= 0) {
805 	text_width += tfm_get_width(font->tfm_id, strptr[i]);
806       }
807     }
808     text_width *= font->pt_size;
809 
810     pdf_dev_set_string((spt_t)(cp.x * dev_unit_dviunit()),
811 		       (spt_t)(cp.y * dev_unit_dviunit()),
812 		       ustr, length * 2,
813 		       (spt_t)(text_width*dev_unit_dviunit()),
814 		       font->font_id, 0);
815     RELEASE(ustr);
816   } else {
817 #define FWBASE ((double) (1<<20))
818     if (font->tfm_id >= 0) {
819       text_width = (double) tfm_string_width(font->tfm_id, strptr, length)/FWBASE;
820       text_width *= font->pt_size;
821     }
822     pdf_dev_set_string((spt_t)(cp.x * dev_unit_dviunit()),
823 		       (spt_t)(cp.y * dev_unit_dviunit()),
824 		       strptr, length,
825 		       (spt_t)(text_width*dev_unit_dviunit()),
826 		       font->font_id, 0);
827   }
828 
829   if (pdf_dev_get_font_wmode(font->font_id)) {
830     pdf_dev_rmoveto(0.0, -text_width);
831   } else {
832     pdf_dev_rmoveto(text_width, 0.0);
833   }
834 
835   graphics_mode();
836   pdf_release_obj(text_str);
837 
838   return 0;
839 }
840 
841 static int
do_mpost_bind_def(const char * ps_code,double x_user,double y_user)842 do_mpost_bind_def (const char *ps_code, double x_user, double y_user)
843 {
844   int   error = 0;
845   const char *start, *end;
846 
847   start = ps_code;
848   end   = start + strlen(start);
849 
850   error = mp_parse_body(&start, end, x_user, y_user);
851 
852   return error;
853 }
854 
855 static int
do_texfig_operator(int opcode,double x_user,double y_user)856 do_texfig_operator (int opcode, double x_user, double y_user)
857 {
858   static transform_info fig_p;
859   static int in_tfig = 0;
860   static int xobj_id = -1;
861   static int count   = 0;
862   double values[6];
863   int    error = 0;
864 
865   switch (opcode) {
866   case STEXFIG:
867     error = pop_get_numbers(values, 6);
868     if (!error) {
869       double   dvi2pts;
870       char     resname[256];
871 
872       transform_info_clear(&fig_p);
873       dvi2pts = 1.0/dev_unit_dviunit();
874 
875       fig_p.width    =  values[0] * dvi2pts;
876       fig_p.height   =  values[1] * dvi2pts;
877       fig_p.bbox.llx =  values[2] * dvi2pts;
878       fig_p.bbox.lly = -values[3] * dvi2pts;
879       fig_p.bbox.urx =  values[4] * dvi2pts;
880       fig_p.bbox.ury = -values[5] * dvi2pts;
881       fig_p.flags   |= INFO_HAS_USER_BBOX;
882 
883       sprintf(resname, "__tf%d__", count);
884       xobj_id = pdf_doc_begin_grabbing(resname,
885 				       fig_p.bbox.llx, fig_p.bbox.ury, &fig_p.bbox);
886 
887       in_tfig = 1;
888       count++;
889     }
890     break;
891   case ETEXFIG:
892     if (!in_tfig)
893       ERROR("endTexFig without valid startTexFig!.");
894 
895     pdf_doc_end_grabbing(NULL);
896     pdf_dev_put_image(xobj_id, &fig_p, x_user, y_user);
897     in_tfig = 0;
898     break;
899   default:
900     error = 1;
901   }
902 
903   return error;
904 }
905 
906 /*
907  * buggy...
908  */
909 
910 /*
911  * CTM(Current Transformation Matrix) means the transformation of User Space
912  * to Device Space coordinates. Because DVIPDFMx does not know the resolution
913  * of Device Space, we assume that the resolution is 1/1000.
914  */
915 #define DEVICE_RESOLUTION 1000
916 static int
ps_dev_CTM(pdf_tmatrix * M)917 ps_dev_CTM (pdf_tmatrix *M)
918 {
919   pdf_dev_currentmatrix(M);
920   M->a *= DEVICE_RESOLUTION; M->b *= DEVICE_RESOLUTION;
921   M->c *= DEVICE_RESOLUTION; M->d *= DEVICE_RESOLUTION;
922   M->e *= DEVICE_RESOLUTION; M->f *= DEVICE_RESOLUTION;
923 
924   return 0;
925 }
926 
927 /*
928  * Again, the only piece that needs x_user and y_user is
929  * that piece dealing with texfig.
930  */
931 static int
do_operator(const char * token,double x_user,double y_user)932 do_operator (const char *token, double x_user, double y_user)
933 {
934   int         error  = 0;
935   int         opcode = 0;
936   double      values[12];
937   pdf_obj    *tmp = NULL;
938   pdf_tmatrix matrix;
939   pdf_coord   cp;
940   pdf_color   color;
941 
942 #define PUSH(o) { \
943   if (top_stack < PS_STACK_SIZE) { \
944     stack[top_stack++] = (o); \
945   } else { \
946     WARN("PS stack overflow including MetaPost file or inline PS code"); \
947     error=1; \
948     break;\
949   } \
950 }
951 
952   opcode = get_opcode(token);
953 
954   switch (opcode) {
955 
956     /*
957      * Arithmetic operators
958      */
959   case ADD:
960     error = pop_get_numbers(values, 2);
961     if (!error)
962       PUSH(pdf_new_number(values[0] + values[1]));
963     break;
964   case MUL:
965     error = pop_get_numbers(values, 2);
966     if (!error)
967       PUSH(pdf_new_number(values[0]*values[1]));
968     break;
969   case NEG:
970     error = pop_get_numbers(values, 1);
971     if (!error)
972       PUSH(pdf_new_number(-values[0]));
973     break;
974   case SUB:
975     error = pop_get_numbers(values, 2);
976     if (!error)
977       PUSH(pdf_new_number(values[0] - values[1]));
978     break;
979   case DIV:
980     error = pop_get_numbers(values, 2);
981     if (!error)
982       PUSH(pdf_new_number(values[0]/values[1]));
983     break;
984   case TRUNCATE: /* Round toward zero. */
985     error = pop_get_numbers(values, 1);
986     if (!error)
987       PUSH(pdf_new_number(((values[0] > 0) ? floor(values[0]) : ceil(values[0]))));
988     break;
989 
990     /* Stack operation */
991   case CLEAR:
992     error = do_clear();
993     break;
994   case POP:
995     tmp = POP_STACK();
996     if (tmp)
997       pdf_release_obj(tmp);
998     break;
999   case EXCH:
1000     error = do_exch();
1001     break;
1002 
1003     /* Path construction */
1004   case MOVETO:
1005     error = pop_get_numbers(values, 2);
1006     if (!error)
1007       error = pdf_dev_moveto(values[0], values[1]);
1008     break;
1009   case RMOVETO:
1010     error = pop_get_numbers(values, 2);
1011     if (!error)
1012       error = pdf_dev_rmoveto(values[0], values[1]);
1013     break;
1014   case LINETO:
1015     error = pop_get_numbers(values, 2);
1016     if (!error)
1017       error = pdf_dev_lineto(values[0], values[1]);
1018     break;
1019   case RLINETO:
1020     error = pop_get_numbers(values, 2);
1021     if (!error)
1022       error = pdf_dev_rlineto(values[0], values[1]);
1023     break;
1024   case CURVETO:
1025     error = pop_get_numbers(values, 6);
1026     if (!error)
1027       error = pdf_dev_curveto(values[0], values[1],
1028 			      values[2], values[3],
1029 			      values[4], values[5]);
1030     break;
1031   case RCURVETO:
1032     error = pop_get_numbers(values, 6);
1033     if (!error)
1034       error = pdf_dev_rcurveto(values[0], values[1],
1035 			       values[2], values[3],
1036 			       values[4], values[5]);
1037     break;
1038   case CLOSEPATH:
1039     error = pdf_dev_closepath();
1040     break;
1041   case ARC:
1042     error = pop_get_numbers(values, 5);
1043     if (!error)
1044       error = pdf_dev_arc(values[0], values[1],
1045 			  values[2], /* rad */
1046 			  values[3], values[4]);
1047     break;
1048   case ARCN:
1049     error = pop_get_numbers(values, 5);
1050     if (!error)
1051       error = pdf_dev_arcn(values[0], values[1],
1052 			   values[2], /* rad */
1053 			   values[3], values[4]);
1054     break;
1055 
1056   case NEWPATH:
1057     pdf_dev_newpath();
1058     break;
1059   case STROKE:
1060     /* fill rule not supported yet */
1061     pdf_dev_flushpath('S', PDF_FILL_RULE_NONZERO);
1062     break;
1063   case FILL:
1064     pdf_dev_flushpath('f', PDF_FILL_RULE_NONZERO);
1065     break;
1066 
1067   case CLIP:
1068     error = pdf_dev_clip();
1069     break;
1070   case EOCLIP:
1071     error = pdf_dev_eoclip();
1072     break;
1073 
1074     /* Graphics state operators: */
1075   case GSAVE:
1076     error = pdf_dev_gsave();
1077     save_font();
1078     break;
1079   case GRESTORE:
1080     error = pdf_dev_grestore();
1081     restore_font();
1082     break;
1083 
1084   case CONCAT:
1085     tmp   = POP_STACK();
1086     error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1087     tmp   = NULL;
1088     if (error)
1089       WARN("Missing array before \"concat\".");
1090     else {
1091       pdf_setmatrix(&matrix,
1092 		    values[0], values[1],
1093 		    values[2], values[3],
1094 		    values[4], values[5]);
1095       error = pdf_dev_concat(&matrix);
1096     }
1097     break;
1098   case SCALE:
1099     error = pop_get_numbers(values, 2);
1100     if (!error) {
1101       switch (mp_cmode) {
1102 #ifndef WITHOUT_ASCII_PTEX
1103       case MP_CMODE_PTEXVERT:
1104 	pdf_setmatrix(&matrix,
1105 		      values[1], 0.0,
1106 		      0.0      , values[0],
1107 		      0.0      , 0.0);
1108 	break;
1109 #endif /* !WITHOUT_ASCII_PTEX */
1110       default:
1111 	pdf_setmatrix(&matrix,
1112 		      values[0], 0.0,
1113 		      0.0      , values[1],
1114 		      0.0      , 0.0);
1115 	break;
1116       }
1117 
1118       error = pdf_dev_concat(&matrix);
1119     }
1120     break;
1121     /* Positive angle means clock-wise direction in graphicx-dvips??? */
1122   case ROTATE:
1123     error = pop_get_numbers(values, 1);
1124     if (!error) {
1125       values[0] = values[0] * M_PI / 180;
1126 
1127       switch (mp_cmode) {
1128       case MP_CMODE_DVIPSK:
1129       case MP_CMODE_MPOST: /* Really? */
1130 #ifndef WITHOUT_ASCII_PTEX
1131       case MP_CMODE_PTEXVERT:
1132 #endif /* !WITHOUT_ASCII_PTEX */
1133 	pdf_setmatrix(&matrix,
1134 		      cos(values[0]), -sin(values[0]),
1135 		      sin(values[0]),  cos(values[0]),
1136 		      0.0,             0.0);
1137 	break;
1138       default:
1139 	pdf_setmatrix(&matrix,
1140 		      cos(values[0]) , sin(values[0]),
1141 		      -sin(values[0]), cos(values[0]),
1142 		      0.0,             0.0);
1143 	break;
1144       }
1145       error = pdf_dev_concat(&matrix);
1146     }
1147     break;
1148   case TRANSLATE:
1149     error = pop_get_numbers(values, 2);
1150     if (!error) {
1151       pdf_setmatrix(&matrix,
1152 		    1.0,       0.0,
1153 		    0.0,       1.0,
1154 		    values[0], values[1]);
1155       error = pdf_dev_concat(&matrix);
1156     }
1157     break;
1158 
1159   case SETDASH:
1160     error = pop_get_numbers(values, 1);
1161     if (!error) {
1162       pdf_obj *pattern, *dash;
1163       int      i, num_dashes;
1164       double   dash_values[PDF_DASH_SIZE_MAX];
1165       double   offset;
1166 
1167       offset  = values[0];
1168       pattern = POP_STACK();
1169       if (!PDF_OBJ_ARRAYTYPE(pattern)) {
1170 	if (pattern)
1171 	  pdf_release_obj(pattern);
1172 	error = 1;
1173 	break;
1174       }
1175       num_dashes = pdf_array_length(pattern);
1176       if (num_dashes > PDF_DASH_SIZE_MAX) {
1177 	WARN("Too many dashes...");
1178 	pdf_release_obj(pattern);
1179 	error = 1;
1180 	break;
1181       }
1182       for (i = 0;
1183 	   i < num_dashes && !error ; i++) {
1184 	dash = pdf_get_array(pattern, i);
1185 	if (!PDF_OBJ_NUMBERTYPE(dash))
1186 	  error = 1;
1187 	else {
1188 	  dash_values[i] = pdf_number_value(dash);
1189 	}
1190       }
1191       pdf_release_obj(pattern);
1192       if (!error) {
1193 	error = pdf_dev_setdash(num_dashes, dash_values, offset);
1194       }
1195     }
1196     break;
1197   case SETLINECAP:
1198     error = pop_get_numbers(values, 1);
1199     if (!error)
1200       error = pdf_dev_setlinecap((int)values[0]);
1201     break;
1202   case SETLINEJOIN:
1203     error = pop_get_numbers(values, 1);
1204     if (!error)
1205       error = pdf_dev_setlinejoin((int)values[0]);
1206     break;
1207   case SETLINEWIDTH:
1208     error = pop_get_numbers(values, 1);
1209     if (!error)
1210       error = pdf_dev_setlinewidth(values[0]);
1211     break;
1212   case SETMITERLIMIT:
1213     error = pop_get_numbers(values, 1);
1214     if (!error)
1215       error = pdf_dev_setmiterlimit(values[0]);
1216     break;
1217 
1218   case SETCMYKCOLOR:
1219     error = pop_get_numbers(values, 4);
1220     /* Not handled properly */
1221     if (!error) {
1222       pdf_color_cmykcolor(&color,
1223 			  values[0], values[1],
1224 			  values[2], values[3]);
1225       pdf_dev_set_strokingcolor(&color);
1226       pdf_dev_set_nonstrokingcolor(&color);
1227     }
1228     break;
1229   case SETGRAY:
1230     /* Not handled properly */
1231     error = pop_get_numbers(values, 1);
1232     if (!error) {
1233       pdf_color_graycolor(&color, values[0]);
1234       pdf_dev_set_strokingcolor(&color);
1235       pdf_dev_set_nonstrokingcolor(&color);
1236     }
1237     break;
1238   case SETRGBCOLOR:
1239     error = pop_get_numbers(values, 3);
1240     if (!error) {
1241       pdf_color_rgbcolor(&color,
1242 			 values[0], values[1], values[2]);
1243       pdf_dev_set_strokingcolor(&color);
1244       pdf_dev_set_nonstrokingcolor(&color);
1245     }
1246     break;
1247 
1248   case SHOWPAGE: /* Let's ignore this for now */
1249     break;
1250 
1251   case CURRENTPOINT:
1252     error = pdf_dev_currentpoint(&cp);
1253     if (!error) {
1254       PUSH(pdf_new_number(cp.x));
1255       PUSH(pdf_new_number(cp.y));
1256     }
1257     break;
1258 
1259   case DTRANSFORM:
1260     {
1261       int  has_matrix = 0;
1262 
1263       tmp = POP_STACK();
1264       if (PDF_OBJ_ARRAYTYPE(tmp)) {
1265 	error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1266 	tmp   = NULL;
1267 	if (error)
1268 	  break;
1269 	pdf_setmatrix(&matrix,
1270 		      values[0], values[1],
1271 		      values[2], values[3],
1272 		      values[4], values[5]);
1273 	tmp = POP_STACK();
1274 	has_matrix = 1;
1275       }
1276 
1277       if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1278 	error = 1;
1279 	break;
1280       }
1281       cp.y = pdf_number_value(tmp);
1282       pdf_release_obj(tmp);
1283 
1284       tmp = POP_STACK();
1285       if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1286 	error = 1;
1287 	break;
1288       }
1289       cp.x = pdf_number_value(tmp);
1290       pdf_release_obj(tmp);
1291 
1292       if (!has_matrix) {
1293 	ps_dev_CTM(&matrix); /* Here, we need real PostScript CTM */
1294       }
1295       pdf_dev_dtransform(&cp, &matrix);
1296       PUSH(pdf_new_number(cp.x));
1297       PUSH(pdf_new_number(cp.y));
1298     }
1299     break;
1300 
1301   case IDTRANSFORM:
1302     {
1303       int  has_matrix = 0;
1304 
1305       tmp = POP_STACK();
1306       if (PDF_OBJ_ARRAYTYPE(tmp)) {
1307 	error = cvr_array(tmp, values, 6); /* This does pdf_release_obj() */
1308 	tmp   = NULL;
1309 	if (error)
1310 	  break;
1311 	pdf_setmatrix(&matrix,
1312 		      values[0], values[1],
1313 		      values[2], values[3],
1314 		      values[4], values[5]);
1315 	tmp = POP_STACK();
1316 	has_matrix = 1;
1317       }
1318 
1319       if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1320 	error = 1;
1321 	break;
1322       }
1323       cp.y = pdf_number_value(tmp);
1324       pdf_release_obj(tmp);
1325 
1326       tmp = POP_STACK();
1327       if (!PDF_OBJ_NUMBERTYPE(tmp)) {
1328 	error = 1;
1329 	break;
1330       }
1331       cp.x = pdf_number_value(tmp);
1332       pdf_release_obj(tmp);
1333 
1334       if (!has_matrix) {
1335 	ps_dev_CTM(&matrix); /* Here, we need real PostScript CTM */
1336       }
1337       pdf_dev_idtransform(&cp, &matrix);
1338       PUSH(pdf_new_number(cp.x));
1339       PUSH(pdf_new_number(cp.y));
1340       break;
1341     }
1342 
1343   case FINDFONT:
1344     error = do_findfont();
1345     break;
1346   case SCALEFONT:
1347     error = do_scalefont();
1348     break;
1349   case SETFONT:
1350     error = do_setfont();
1351     break;
1352   case CURRENTFONT:
1353     error = do_currentfont();
1354     break;
1355 
1356   case SHOW:
1357     error = do_show();
1358     break;
1359 
1360   case STRINGWIDTH:
1361     error = 1;
1362     break;
1363 
1364     /* Extensions */
1365   case FSHOW:
1366     error = do_mpost_bind_def("exch findfont exch scalefont setfont show", x_user, y_user);
1367     break;
1368   case STEXFIG:
1369   case ETEXFIG:
1370     error = do_texfig_operator(opcode, x_user, y_user);
1371     break;
1372   case HLW:
1373     error = do_mpost_bind_def("0 dtransform exch truncate exch idtransform pop setlinewidth", x_user, y_user);
1374     break;
1375   case VLW:
1376     error = do_mpost_bind_def("0 exch dtransform truncate idtransform setlinewidth pop", x_user, y_user);
1377     break;
1378   case RD:
1379     error = do_mpost_bind_def("[] 0 setdash", x_user, y_user);
1380     break;
1381   case B:
1382     error = do_mpost_bind_def("gsave fill grestore", x_user, y_user);
1383     break;
1384 
1385   case DEF:
1386     tmp = POP_STACK();
1387     tmp = POP_STACK();
1388     /* do nothing; not implemented yet */
1389     break;
1390 
1391   default:
1392     if (is_fontname(token)) {
1393       PUSH(pdf_new_name(token));
1394     } else {
1395       WARN("Unknown token \"%s\"", token);
1396       error = 1;
1397     }
1398     break;
1399   }
1400 
1401   return error;
1402 }
1403 
1404 /*
1405  * The only sections that need to know x_user and y _user are those
1406  * dealing with texfig.
1407  */
1408 static int
mp_parse_body(const char ** start,const char * end,double x_user,double y_user)1409 mp_parse_body (const char **start, const char *end, double x_user, double y_user)
1410 {
1411   char    *token;
1412   pdf_obj *obj;
1413   int      error = 0;
1414 
1415   skip_white(start, end);
1416   while (*start < end && !error) {
1417     if (isdigit((unsigned char)**start) ||
1418 	(*start < end - 1 &&
1419 	 (**start == '+' || **start == '-' || **start == '.' ))) {
1420       double value;
1421       char  *next;
1422 
1423       value = strtod(*start, &next);
1424       if (next < end && !strchr("<([{/%", *next) && !isspace((unsigned char)*next)) {
1425 	WARN("Unkown PostScript operator.");
1426 	dump(*start, next);
1427 	error = 1;
1428       } else {
1429 	PUSH(pdf_new_number(value));
1430 	*start = next;
1431       }
1432       /*
1433        * PDF parser can't handle PS operator inside arrays.
1434        * This shouldn't use parse_pdf_array().
1435        */
1436     } else if (**start == '[' &&
1437 	       (obj = parse_pdf_array(start, end, NULL))) {
1438       PUSH(obj);
1439       /* This cannot handle ASCII85 string. */
1440     } else if (*start < end - 1 &&
1441 	       (**start == '<' && *(*start+1) == '<') &&
1442 	       (obj = parse_pdf_dict(start, end, NULL))) {
1443       PUSH(obj);
1444     } else if ((**start == '(' || **start == '<') &&
1445 	       (obj = parse_pdf_string (start, end))) {
1446       PUSH(obj);
1447     } else if (**start == '/' &&
1448 	       (obj = parse_pdf_name(start, end))) {
1449       PUSH(obj);
1450     } else {
1451       token = parse_ident(start, end);
1452       if (!token)
1453 	error = 1;
1454       else {
1455 	error = do_operator(token, x_user, y_user);
1456 	RELEASE(token);
1457       }
1458     }
1459     skip_white(start, end);
1460   }
1461 
1462   return error;
1463 }
1464 
1465 void
mps_eop_cleanup(void)1466 mps_eop_cleanup (void)
1467 {
1468   clear_fonts();
1469   do_clear();
1470 }
1471 
1472 int
mps_stack_depth(void)1473 mps_stack_depth (void)
1474 {
1475   return top_stack;
1476 }
1477 
1478 int
mps_exec_inline(const char ** p,const char * endptr,double x_user,double y_user)1479 mps_exec_inline (const char **p, const char *endptr,
1480 		 double x_user, double y_user)
1481 {
1482   int  error;
1483   int  dirmode, autorotate;
1484 
1485   /* Compatibility for dvipsk. */
1486   dirmode = pdf_dev_get_dirmode();
1487   if (dirmode) {
1488     mp_cmode = MP_CMODE_PTEXVERT;
1489   } else {
1490     mp_cmode = MP_CMODE_DVIPSK;
1491   }
1492 
1493   autorotate = pdf_dev_get_param(PDF_DEV_PARAM_AUTOROTATE);
1494   pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, 0);
1495   //pdf_color_push(); /* ... */
1496 
1497   /* Comment in dvipdfm:
1498    * Remember that x_user and y_user are off by 0.02 %
1499    */
1500   pdf_dev_moveto(x_user, y_user);
1501   error = mp_parse_body(p, endptr, x_user, y_user);
1502 
1503   //pdf_color_pop(); /* ... */
1504   pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, autorotate);
1505   pdf_dev_set_dirmode(dirmode);
1506 
1507   return error;
1508 }
1509 
1510 /* mp inclusion is a bit of a hack.  The routine
1511  * starts a form at the lower left corner of
1512  * the page and then calls begin_form_xobj telling
1513  * it to record the image drawn there and bundle it
1514  * up in an xojbect.  This allows us to use the coordinates
1515  * in the MP file directly.  This appears to be the
1516  * easiest way to be able to use the pdf_dev_set_string()
1517  * command (with its scaled and extended fonts) without
1518  * getting all confused about the coordinate system.
1519  * After the xobject is created, the whole thing can
1520  * be scaled any way the user wants
1521  */
1522 
1523 /* Should implement save and restore. */
1524 int
mps_include_page(const char * ident,FILE * fp)1525 mps_include_page (const char *ident, FILE *fp)
1526 {
1527   int        form_id;
1528   xform_info info;
1529   int        st_depth, gs_depth;
1530   char      *buffer;
1531   const char *p, *endptr;
1532   long       length, nb_read;
1533   int        dirmode, autorotate, error;
1534 
1535   rewind(fp);
1536 
1537   length = file_size(fp);
1538   if (length < 1) {
1539     WARN("Can't read any byte in the MPS file.");
1540     return -1;
1541   }
1542 
1543   buffer = NEW(length + 1, char);
1544   buffer[length] = '\0';
1545   p      = buffer;
1546   endptr = p + length;
1547 
1548   while (length > 0) {
1549     nb_read = fread(buffer, sizeof(char), length, fp);
1550     if (nb_read < 0) {
1551       RELEASE(buffer);
1552       WARN("Reading file failed...");
1553       return -1;
1554     }
1555     length -= nb_read;
1556   }
1557 
1558   error = mps_scan_bbox(&p, endptr, &(info.bbox));
1559   if (error) {
1560     WARN("Error occured while scanning MetaPost file headers: Could not find BoundingBox.");
1561     RELEASE(buffer);
1562     return -1;
1563   }
1564   skip_prolog(&p, endptr);
1565 
1566   dirmode    = pdf_dev_get_dirmode();
1567   autorotate = pdf_dev_get_param(PDF_DEV_PARAM_AUTOROTATE);
1568   pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, 0);
1569   //pdf_color_push();
1570 
1571   form_id  = pdf_doc_begin_grabbing(ident, Xorigin, Yorigin, &(info.bbox));
1572 
1573   mp_cmode = MP_CMODE_MPOST;
1574   gs_depth = pdf_dev_current_depth();
1575   st_depth = mps_stack_depth();
1576   /* At this point the gstate must be initialized, since it starts a new
1577    * XObject. Note that it increase gs_depth by 1. */
1578   pdf_dev_push_gstate();
1579 
1580   error = mp_parse_body(&p, endptr, 0.0, 0.0);
1581   RELEASE(buffer);
1582 
1583   if (error) {
1584     WARN("Errors occured while interpreting MPS file.");
1585     /* WARN("Leaving garbage in output PDF file."); */
1586     form_id = -1;
1587   }
1588 
1589   /* It's time to pop the new gstate above. */
1590   pdf_dev_pop_gstate();
1591   mps_stack_clear_to (st_depth);
1592   pdf_dev_grestore_to(gs_depth);
1593 
1594   pdf_doc_end_grabbing(NULL);
1595 
1596   //pdf_color_pop();
1597   pdf_dev_set_param(PDF_DEV_PARAM_AUTOROTATE, autorotate);
1598   pdf_dev_set_dirmode(dirmode);
1599 
1600   return form_id;
1601 }
1602 
1603 int
mps_do_page(FILE * image_file)1604 mps_do_page (FILE *image_file)
1605 {
1606   int       error = 0;
1607   pdf_rect  bbox;
1608   char     *buffer;
1609   const char *start, *end;
1610   long      size;
1611   int       dir_mode;
1612 
1613   rewind(image_file);
1614   if ((size = file_size(image_file)) == 0) {
1615     WARN("Can't read any byte in the MPS file.");
1616     return -1;
1617   }
1618 
1619   buffer = NEW(size+1, char);
1620   fread(buffer, sizeof(char), size, image_file);
1621   buffer[size] = 0;
1622   start = buffer;
1623   end   = buffer + size;
1624 
1625   error = mps_scan_bbox(&start, end, &bbox);
1626   if (error) {
1627     WARN("Error occured while scanning MetaPost file headers: Could not find BoundingBox.");
1628     RELEASE(buffer);
1629     return -1;
1630   }
1631 
1632   mp_cmode = MP_CMODE_MPOST;
1633 
1634   pdf_doc_begin_page  (1.0, -Xorigin, -Yorigin); /* scale, xorig, yorig */
1635   pdf_doc_set_mediabox(pdf_doc_current_page_number(), &bbox);
1636 
1637   dir_mode = pdf_dev_get_dirmode();
1638   pdf_dev_set_autorotate(0);
1639 
1640   skip_prolog(&start, end);
1641 
1642   error = mp_parse_body(&start, end, 0.0, 0.0);
1643 
1644   if (error) {
1645     WARN("Errors occured while interpreting MetaPost file.");
1646   }
1647 
1648   pdf_dev_set_autorotate(1);
1649   pdf_dev_set_dirmode(dir_mode);
1650 
1651   pdf_doc_end_page();
1652 
1653   RELEASE(buffer);
1654 
1655   /*
1656    * The reason why we don't return XObject itself is
1657    * PDF inclusion may not be made so.
1658    */
1659   return (error ? -1 : 0);
1660 }
1661 
1662 int
check_for_mp(FILE * image_file)1663 check_for_mp (FILE *image_file)
1664 {
1665   int try_count = 10;
1666 
1667   rewind (image_file);
1668   mfgets(work_buffer, WORK_BUFFER_SIZE, image_file);
1669   if (strncmp(work_buffer, "%!PS", 4))
1670     return 0;
1671 
1672   while (try_count > 0) {
1673     mfgets(work_buffer, WORK_BUFFER_SIZE, image_file);
1674     if (!strncmp(work_buffer, "%%Creator:", 10)) {
1675       if (strlen(work_buffer+10) >= 8 &&
1676 	  strstr(work_buffer+10, "MetaPost"))
1677 	break;
1678     }
1679     try_count--;
1680   }
1681 
1682   return ((try_count > 0) ? 1 : 0);
1683 }
1684