1 /*
2 Copyright 1996-2014 Han The Thanh, <thanh@pdftex.org>
3 
4 This file is part of pdfTeX.
5 
6 pdfTeX is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 
11 pdfTeX is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along
17 with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <w2c/config.h>		/* for large file support */
21 #include <sys/types.h>
22 #include <regex.h>
23 #include <kpathsea/config.h>
24 #include <kpathsea/c-proto.h>
25 #include <kpathsea/c-stat.h>
26 #include <kpathsea/c-fopen.h>
27 #include <kpathsea/version.h>
28 #include <string.h>
29 #include <time.h>
30 #include <float.h>              /* for DBL_EPSILON */
31 #include "md5.h"
32 #include "zlib.h"
33 #include "ptexlib.h"
34 #include "png.h"
35 #ifdef POPPLER_VERSION
36 #include "poppler-config.h"
37 #define xpdfVersion POPPLER_VERSION
38 #define xpdfString "poppler"
39 #else
40 #include "xpdf/config.h"        /* just to get the xpdf version */
41 #define xpdfString "xpdf"
42 #endif
43 
44 #define check_nprintf(size_get, size_want) \
45     if ((unsigned)(size_get) >= (unsigned)(size_want)) \
46         pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
47 
48 char *cur_file_name = NULL;
49 strnumber last_tex_string;
50 static char print_buf[PRINTF_BUF_SIZE];
51 static char *jobname_cstr = NULL;
52 static char *job_id_string = NULL;
53 
54 size_t last_ptr_index;          /* for use with alloc_array */
55 
56 /* define fb_ptr, fb_array & fb_limit */
57 typedef char fb_entry;
58 define_array(fb);
59 
60 /* define char_ptr, char_array & char_limit */
61 typedef char char_entry;
62 define_array(char);
63 
64 /* define vf_e_fnts_ptr, vf_e_fnts_array & vf_e_fnts_limit */
65 typedef integer vf_e_fnts_entry;
66 define_array(vf_e_fnts);
67 
68 /* define vf_i_fnts_ptr, vf_i_fnts_array & vf_i_fnts_limit */
69 typedef internalfontnumber vf_i_fnts_entry;
70 define_array(vf_i_fnts);
71 
fb_offset(void)72 integer fb_offset(void)
73 {
74     return fb_ptr - fb_array;
75 }
76 
fb_seek(integer offset)77 void fb_seek(integer offset)
78 {
79     fb_ptr = fb_array + offset;
80 }
81 
fb_putchar(eightbits b)82 void fb_putchar(eightbits b)
83 {
84     alloc_array(fb, 1, SMALL_ARRAY_SIZE);
85     *fb_ptr++ = b;
86 }
87 
fb_flush(void)88 void fb_flush(void)
89 {
90     fb_entry *p;
91     integer n;
92     for (p = fb_array; p < fb_ptr;) {
93         n = pdfbufsize - pdfptr;
94         if (fb_ptr - p < n)
95             n = fb_ptr - p;
96         memcpy(pdfbuf + pdfptr, p, (unsigned) n);
97         pdfptr += n;
98         if (pdfptr == pdfbufsize)
99             pdfflush();
100         p += n;
101     }
102     fb_ptr = fb_array;
103 }
104 
105 #define SUBSET_TAG_LENGTH 6
106 
make_subset_tag(fd_entry * fd)107 void make_subset_tag(fd_entry * fd)
108 {
109     int i, j = 0, a[SUBSET_TAG_LENGTH];
110     md5_state_t pms;
111     char *glyph;
112     struct avl_traverser t;
113     md5_byte_t digest[16];
114     void **aa;
115     static struct avl_table *st_tree = NULL;
116     if (st_tree == NULL)
117         st_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
118     assert(fd != NULL);
119     assert(fd->gl_tree != NULL);
120     assert(fd->fontname != NULL);
121     assert(fd->subset_tag == NULL);
122     fd->subset_tag = xtalloc(SUBSET_TAG_LENGTH + 1, char);
123     do {
124         md5_init(&pms);
125         avl_t_init(&t, fd->gl_tree);
126         for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL;
127              glyph = (char *) avl_t_next(&t)) {
128             md5_append(&pms, (md5_byte_t *) glyph, strlen(glyph));
129             md5_append(&pms, (const md5_byte_t *) " ", 1);
130         }
131         md5_append(&pms, (md5_byte_t *) fd->fontname, strlen(fd->fontname));
132         md5_append(&pms, (md5_byte_t *) & j, sizeof(int));      /* to resolve collision */
133         md5_finish(&pms, digest);
134         for (a[0] = 0, i = 0; i < 13; i++)
135             a[0] += digest[i];
136         for (i = 1; i < SUBSET_TAG_LENGTH; i++)
137             a[i] = a[i - 1] - digest[i - 1] + digest[(i + 12) % 16];
138         for (i = 0; i < SUBSET_TAG_LENGTH; i++)
139             fd->subset_tag[i] = a[i] % 26 + 'A';
140         fd->subset_tag[SUBSET_TAG_LENGTH] = '\0';
141         j++;
142         assert(j < 100);
143     }
144     while ((char *) avl_find(st_tree, fd->subset_tag) != NULL);
145     aa = avl_probe(st_tree, fd->subset_tag);
146     assert(aa != NULL);
147     if (j > 2)
148         pdftex_warn
149             ("\nmake_subset_tag(): subset-tag collision, resolved in round %d.\n",
150              j);
151 }
152 
pdf_puts(const char * s)153 void pdf_puts(const char *s)
154 {
155     pdfroom(strlen(s) + 1);
156     while (*s)
157         pdfbuf[pdfptr++] = *s++;
158     pdflastbyte = s[-1];
159 }
160 
pdf_newline(void)161 void pdf_newline(void)
162 {
163     if (pdflastbyte != '\n')
164         pdf_puts("\n");
165 }
166 
167 __attribute__ ((format(printf, 1, 2)))
pdf_printf(const char * fmt,...)168 void pdf_printf(const char *fmt, ...)
169 {
170     va_list args;
171     va_start(args, fmt);
172     vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
173     pdf_puts(print_buf);
174     va_end(args);
175 }
176 
maketexstring(const char * s)177 strnumber maketexstring(const char *s)
178 {
179     size_t l;
180     if (s == NULL || *s == 0)
181         return getnullstr();
182     l = strlen(s);
183     check_buf(poolptr + l, poolsize);
184     while (l-- > 0)
185         strpool[poolptr++] = *s++;
186     last_tex_string = makestring();
187     return last_tex_string;
188 }
189 
190 __attribute__ ((format(printf, 1, 2)))
tex_printf(const char * fmt,...)191 void tex_printf(const char *fmt, ...)
192 {
193     va_list args;
194     va_start(args, fmt);
195     vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
196     print(maketexstring(print_buf));
197     flushstr(last_tex_string);
198     xfflush(stdout);
199     va_end(args);
200 }
201 
202 /* Helper for pdftex_fail. */
safe_print(const char * str)203 static void safe_print(const char *str)
204 {
205     const char *c;
206     for (c = str; *c; ++c)
207         print(*c);
208 }
209 
removepdffile(void)210 void removepdffile(void)
211 {
212     if (!kpathsea_debug && outputfilename && !fixedpdfdraftmode) {
213         xfclose(pdffile, makecstring(outputfilename));
214         remove(makecstring(outputfilename));
215     }
216 }
217 
218 /* pdftex_fail may be called when a buffer overflow has happened/is
219    happening, therefore may not call mktexstring.  However, with the
220    current implementation it appears that error messages are misleading,
221    possibly because pool overflows are detected too late.
222 
223    The output format of this fuction must be the same as pdf_error in
224    pdftex.web! */
225 __attribute__ ((noreturn, format(printf, 1, 2)))
pdftex_fail(const char * fmt,...)226 void pdftex_fail(const char *fmt, ...)
227 {
228     va_list args;
229     va_start(args, fmt);
230     println();
231     safe_print("!pdfTeX error: ");
232     safe_print(kpse_invocation_name);
233     if (cur_file_name) {
234         safe_print(" (file ");
235         safe_print(cur_file_name);
236         safe_print(")");
237     }
238     safe_print(": ");
239     vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
240     safe_print(print_buf);
241     va_end(args);
242     println();
243     removepdffile();
244     safe_print(" ==> Fatal error occurred, no output PDF file produced!");
245     println();
246     if (kpathsea_debug) {
247         safe_print("kpathsea_debug enabled, calling abort()...");
248         println();
249         abort();
250     } else {
251         exit(EXIT_FAILURE);
252     }
253 }
254 
255 /* The output format of this fuction must be the same as pdf_warn in
256    pdftex.web! */
257 __attribute__ ((format(printf, 1, 2)))
pdftex_warn(const char * fmt,...)258 void pdftex_warn(const char *fmt, ...)
259 {
260     va_list args;
261     va_start(args, fmt);
262     println();
263     println();
264     tex_printf("pdfTeX warning: %s", kpse_invocation_name);
265     if (cur_file_name)
266         tex_printf(" (file %s)", cur_file_name);
267     tex_printf(": ");
268     vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
269     print(maketexstring(print_buf));
270     flushstr(last_tex_string);
271     va_end(args);
272     println();
273 }
274 
garbagewarning(void)275 void garbagewarning(void)
276 {
277     pdftex_warn("dangling objects discarded, no output file produced.");
278     removepdffile();
279 }
280 
setjobid(int year,int month,int day,int time)281 void setjobid(int year, int month, int day, int time)
282 {
283     char *name_string, *format_string, *s;
284     size_t slen;
285     int i;
286 
287     if (job_id_string != NULL)
288         return;
289 
290     name_string = xstrdup(makecstring(jobname));
291     format_string = xstrdup(makecstring(formatident));
292     slen = SMALL_BUF_SIZE +
293         strlen(name_string) +
294         strlen(format_string) +
295         strlen(ptexbanner) +
296         strlen(versionstring) + strlen(kpathsea_version_string);
297     s = xtalloc(slen, char);
298     /* The Web2c version string starts with a space.  */
299     i = snprintf(s, slen,
300                  "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
301                  year, month, day, time / 60, time % 60,
302                  name_string, format_string, ptexbanner,
303                  versionstring, kpathsea_version_string);
304     check_nprintf(i, slen);
305     job_id_string = xstrdup(s);
306     xfree(s);
307     xfree(name_string);
308     xfree(format_string);
309 }
310 
makepdftexbanner(void)311 void makepdftexbanner(void)
312 {
313     static boolean pdftexbanner_init = false;
314     char *s;
315     size_t slen;
316     int i;
317 
318     if (pdftexbanner_init)
319         return;
320 
321     slen = SMALL_BUF_SIZE +
322         strlen(ptexbanner) +
323         strlen(versionstring) + strlen(kpathsea_version_string);
324     s = xtalloc(slen, char);
325     /* The Web2c version string starts with a space.  */
326     i = snprintf(s, slen,
327                  "%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
328     check_nprintf(i, slen);
329     pdftexbanner = maketexstring(s);
330     xfree(s);
331     pdftexbanner_init = true;
332 }
333 
getresnameprefix(void)334 strnumber getresnameprefix(void)
335 {
336 /*     static char name_str[] = */
337 /* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */
338 /* "^_`abcdefghijklmnopqrstuvwxyz|~"; */
339     static char name_str[] =
340         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
341     char prefix[7];             /* make a tag of 6 chars long */
342     unsigned long crc;
343     int i;
344     size_t base = strlen(name_str);
345     crc = crc32(0L, Z_NULL, 0);
346     crc = crc32(crc, (Bytef *) job_id_string, strlen(job_id_string));
347     for (i = 0; i < 6; i++) {
348         prefix[i] = name_str[crc % base];
349         crc /= base;
350     }
351     prefix[6] = 0;
352     return maketexstring(prefix);
353 }
354 
xfwrite(void * ptr,size_t size,size_t nmemb,FILE * stream)355 size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE * stream)
356 {
357     if (fwrite(ptr, size, nmemb, stream) != nmemb)
358         pdftex_fail("fwrite() failed");
359     return nmemb;
360 }
361 
xfflush(FILE * stream)362 int xfflush(FILE * stream)
363 {
364     if (fflush(stream) != 0)
365         pdftex_fail("fflush() failed (%s)", strerror(errno));
366     return 0;
367 }
368 
xgetc(FILE * stream)369 int xgetc(FILE * stream)
370 {
371     int c = getc(stream);
372     if (c < 0 && c != EOF)
373         pdftex_fail("getc() failed (%s)", strerror(errno));
374     return c;
375 }
376 
xputc(int c,FILE * stream)377 int xputc(int c, FILE * stream)
378 {
379     int i = putc(c, stream);
380     if (i < 0)
381         pdftex_fail("putc() failed (%s)", strerror(errno));
382     return i;
383 }
384 
writestreamlength(longinteger length,longinteger offset)385 void writestreamlength(longinteger length, longinteger offset)
386 {
387     if (jobname_cstr == NULL)
388         jobname_cstr = xstrdup(makecstring(jobname));
389     if (fixedpdfdraftmode == 0) {
390         xfseeko(pdffile, (off_t) offset, SEEK_SET, jobname_cstr);
391         fprintf(pdffile, "%" LONGINTEGER_PRI "i", (LONGINTEGER_TYPE) length);
392         xfseeko(pdffile, (off_t) pdfoffset(), SEEK_SET, jobname_cstr);
393     }
394 }
395 
extxnoverd(scaled x,scaled n,scaled d)396 scaled extxnoverd(scaled x, scaled n, scaled d)
397 {
398     double r = (((double) x) * ((double) n)) / ((double) d);
399     if (r > DBL_EPSILON)
400         r += 0.5;
401     else
402         r -= 0.5;
403     if (r >= (double) maxinteger || r <= -(double) maxinteger)
404         pdftex_warn("arithmetic: number too big");
405     return (scaled) r;
406 }
407 
libpdffinish(void)408 void libpdffinish(void)
409 {
410     xfree(fb_array);
411     xfree(char_array);
412     xfree(job_id_string);
413     fm_free();
414     t1_free();
415     enc_free();
416     img_free();
417     vf_free();
418     epdf_free();
419     ttf_free();
420     sfd_free();
421     glyph_unicode_free();
422     zip_free();
423 }
424 
425 /* Converts any string given in in in an allowed PDF string which can be
426  * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and
427  * control characters are octal encoded.
428  * This assumes that the string does not contain any already escaped
429  * characters!
430  */
convertStringToPDFString(const char * in,int len)431 char *convertStringToPDFString(const char *in, int len)
432 {
433     static char pstrbuf[MAX_PSTRING_LEN];
434     char *out = pstrbuf;
435     int i, j = 0, k;
436     char buf[5];
437     for (i = 0; i < len; i++) {
438         check_buf(j + sizeof(buf), MAX_PSTRING_LEN);
439         if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) {
440             /* convert control characters into oct */
441             k = snprintf(buf, sizeof(buf),
442                          "\\%03o", (unsigned int) (unsigned char) in[i]);
443             check_nprintf(k, sizeof(buf));
444             out[j++] = buf[0];
445             out[j++] = buf[1];
446             out[j++] = buf[2];
447             out[j++] = buf[3];
448         } else if ((in[i] == '(') || (in[i] == ')')) {
449             /* escape paranthesis */
450             out[j++] = '\\';
451             out[j++] = in[i];
452         } else if (in[i] == '\\') {
453             /* escape backslash */
454             out[j++] = '\\';
455             out[j++] = '\\';
456         } else {
457             /* copy char :-) */
458             out[j++] = in[i];
459         }
460     }
461     out[j] = '\0';
462     return pstrbuf;
463 }
464 
465 
466 /* Converts any string given in in in an allowed PDF string which can be
467  * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and
468  * control characters are octal encoded.
469  * This assumes that the string does not contain any already escaped
470  * characters!
471  *
472  * See escapename for parameter description.
473  */
escapestring(poolpointer in)474 void escapestring(poolpointer in)
475 {
476     const poolpointer out = poolptr;
477     unsigned char ch;
478     while (in < out) {
479         if (poolptr + 4 >= poolsize) {
480             poolptr = poolsize;
481             /* error by str_toks that calls str_room(1) */
482             return;
483         }
484 
485         ch = (unsigned char) strpool[in++];
486 
487         if ((ch < '!') || (ch > '~')) {
488             /* convert control characters into oct */
489             int i = snprintf((char *) &strpool[poolptr], 5,
490                              "\\%.3o", (unsigned int) ch);
491             check_nprintf(i, 5);
492             poolptr += i;
493             continue;
494         }
495         if ((ch == '(') || (ch == ')') || (ch == '\\')) {
496             /* escape parenthesis and backslash */
497             strpool[poolptr++] = '\\';
498         }
499         /* copy char :-) */
500         strpool[poolptr++] = ch;
501     }
502 }
503 
504 /* Convert any given string in a PDF name using escaping mechanism
505    of PDF 1.2. The result does not include the leading slash.
506 
507    PDF specification 1.6, section 3.2.6 "Name Objects" explains:
508    <blockquote>
509     Beginning with PDF 1.2, any character except null (character code 0) may
510     be included in a name by writing its 2-digit hexadecimal code, preceded
511     by the number sign character (#); see implementation notes 3 and 4 in
512     Appendix H. This syntax is required to represent any of the delimiter or
513     white-space characters or the number sign character itself; it is
514     recommended but not required for characters whose codes are outside the
515     range 33 (!) to 126 (~).
516    </blockquote>
517    The following table shows the conversion that are done by this
518    function:
519      code      result   reason
520      -----------------------------------
521      0         ignored  not allowed
522      1..32     escaped  must for white-space:
523                           9 (tab), 10 (lf), 12 (ff), 13 (cr), 32 (space)
524                         recommended for the other control characters
525      35        escaped  escape char "#"
526      37        escaped  delimiter "%"
527      40..41    escaped  delimiters "(" and ")"
528      47        escaped  delimiter "/"
529      60        escaped  delimiter "<"
530      62        escaped  delimiter ">"
531      91        escaped  delimiter "["
532      93        escaped  delimiter "]"
533      123       escaped  delimiter "{"
534      125       escaped  delimiter "}"
535      127..255  escaped  recommended
536      else      copy     regular characters
537 
538    Parameter "in" is a pointer into the string pool where
539    the input string is located. The output string is written
540    as temporary string right after the input string.
541    Thus at the begin of the procedure the global variable
542    "poolptr" points to the start of the output string and
543    after the end when the procedure returns.
544 */
escapename(poolpointer in)545 void escapename(poolpointer in)
546 {
547     const poolpointer out = poolptr;
548     unsigned char ch;
549     int i;
550 
551     while (in < out) {
552         if (poolptr + 3 >= poolsize) {
553             poolptr = poolsize;
554             /* error by str_toks that calls str_room(1) */
555             return;
556         }
557 
558         ch = (unsigned char) strpool[in++];
559 
560         if ((ch >= 1 && ch <= 32) || ch >= 127) {
561             /* escape */
562             i = snprintf((char *) &strpool[poolptr], 4,
563                          "#%.2X", (unsigned int) ch);
564             check_nprintf(i, 4);
565             poolptr += i;
566             continue;
567         }
568         switch (ch) {
569         case 0:
570             /* ignore */
571             break;
572         case 35:
573         case 37:
574         case 40:
575         case 41:
576         case 47:
577         case 60:
578         case 62:
579         case 91:
580         case 93:
581         case 123:
582         case 125:
583             /* escape */
584             i = snprintf((char *) &strpool[poolptr], 4,
585                          "#%.2X", (unsigned int) ch);
586             check_nprintf(i, 4);
587             poolptr += i;
588             break;
589         default:
590             /* copy */
591             strpool[poolptr++] = ch;
592         }
593     }
594 }
595 
596 /* Convert any given string in a PDF hexadecimal string. The
597    result does not include the angle brackets.
598 
599    This procedure uses uppercase hexadecimal letters.
600 
601    See escapename for description of parameters.
602 */
escapehex(poolpointer in)603 void escapehex(poolpointer in)
604 {
605     const poolpointer out = poolptr;
606     unsigned char ch;
607     int i;
608 
609     while (in < out) {
610         if (poolptr + 2 >= poolsize) {
611             poolptr = poolsize;
612             /* error by str_toks that calls str_room(1) */
613             return;
614         }
615 
616         ch = (unsigned char) strpool[in++];
617 
618         i = snprintf((char *) &strpool[poolptr], 3, "%.2X", (unsigned int) ch);
619         check_nprintf(i, 3);
620         poolptr += 2;
621     }
622 }
623 
624 /* Unescape any given hexadecimal string.
625 
626    Last hex digit can be omitted, it is replaced by zero, see
627    PDF specification.
628 
629    Invalid digits are silently ignored.
630 
631    See escapename for description of parameters.
632 */
unescapehex(poolpointer in)633 void unescapehex(poolpointer in)
634 {
635     const poolpointer out = poolptr;
636     unsigned char ch;
637     unsigned char a = 0;        /* to avoid warning about uninitialized use of a */
638     boolean first = true;
639 
640     while (in < out) {
641         if (poolptr + 1 >= poolsize) {
642             poolptr = poolsize;
643             /* error by str_toks that calls str_room(1) */
644             return;
645         }
646 
647         ch = (unsigned char) strpool[in++];
648 
649         if ((ch >= '0') && (ch <= '9')) {
650             ch -= '0';
651         } else if ((ch >= 'A') && (ch <= 'F')) {
652             ch -= 'A' - 10;
653         } else if ((ch >= 'a') && (ch <= 'f')) {
654             ch -= 'a' - 10;
655         } else {
656             continue;           /* ignore wrong character */
657         }
658 
659         if (first) {
660             a = ch << 4;
661             first = false;
662             continue;
663         }
664 
665         strpool[poolptr++] = a + ch;
666         first = true;
667     }
668     if (!first) {               /* last hex digit is omitted */
669         strpool[poolptr++] = a;
670     }
671 }
672 
673 
674 /* Converts any string given in in in an allowed PDF string which is
675  * hexadecimal encoded;
676  * sizeof(out) should be at least lin*2+1.
677  */
convertStringToHexString(const char * in,char * out,int lin)678 static void convertStringToHexString(const char *in, char *out, int lin)
679 {
680     int i, j, k;
681     char buf[3];
682     j = 0;
683     for (i = 0; i < lin; i++) {
684         k = snprintf(buf, sizeof(buf),
685                      "%02X", (unsigned int) (unsigned char) in[i]);
686         check_nprintf(k, sizeof(buf));
687         out[j++] = buf[0];
688         out[j++] = buf[1];
689     }
690     out[j] = '\0';
691 }
692 
693 /* Compute the ID string as per PDF1.4 9.3:
694   <blockquote>
695     File identifers are defined by the optional ID entry in a PDF file's
696     trailer dictionary (see Section 3.4.4, "File Trailer"; see also
697     implementation note 105 in Appendix H). The value of this entry is an
698     array of two strings. The first string is a permanent identifier based
699     on the contents of the file at the time it was originally created, and
700     does not change when the file is incrementally updated. The second
701     string is a changing identifier based on the file's contents at the
702     time it was last updated. When a file is first written, both
703     identifiers are set to the same value. If both identifiers match when a
704     file reference is resolved, it is very likely that the correct file has
705     been found; if only the first identifier matches, then a different
706     version of the correct file has been found.
707         To help ensure the uniqueness of file identifiers, it is recommend
708     that they be computed using a message digest algorithm such as MD5
709     (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see
710     the Bibliography), using the following information (see implementation
711     note 106 in Appendix H):
712     - The current time
713     - A string representation of the file's location, usually a pathname
714     - The size of the file in bytes
715     - The values of all entries in the file's document information
716       dictionary (see Section 9.2.1,  Document Information Dictionary )
717   </blockquote>
718   This stipulates only that the two IDs must be identical when the file is
719   created and that they should be reasonably unique. Since it's difficult
720   to get the file size at this point in the execution of pdfTeX and
721   scanning the info dict is also difficult, we start with a simpler
722   implementation using just the first two items.
723  */
printID(strnumber filename)724 void printID(strnumber filename)
725 {
726     time_t t;
727     size_t size;
728     char time_str[32];
729     md5_state_t state;
730     md5_byte_t digest[16];
731     char id[64];
732     char *file_name;
733     char pwd[4096];
734     /* start md5 */
735     md5_init(&state);
736     /* get the time */
737     t = time(NULL);
738     size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
739     md5_append(&state, (const md5_byte_t *) time_str, size);
740     /* get the file name */
741     if (getcwd(pwd, sizeof(pwd)) == NULL)
742         pdftex_fail("getcwd() failed (%s), path too long?", strerror(errno));
743 #ifdef WIN32
744     {
745         char *p;
746         for (p = pwd; *p; p++) {
747             if (*p == '\\')
748                 *p = '/';
749             else if (IS_KANJI(p))
750                 p++;
751         }
752     }
753 #endif
754     file_name = makecstring(filename);
755     md5_append(&state, (const md5_byte_t *) pwd, strlen(pwd));
756     md5_append(&state, (const md5_byte_t *) "/", 1);
757     md5_append(&state, (const md5_byte_t *) file_name, strlen(file_name));
758     /* finish md5 */
759     md5_finish(&state, digest);
760     /* write the IDs */
761     convertStringToHexString((char *) digest, id, 16);
762     pdf_printf("/ID [<%s> <%s>]", id, id);
763 }
764 
765 /* Print the /CreationDate entry.
766 
767   PDF Reference, third edition says about the expected date format:
768   <blockquote>
769     3.8.2 Dates
770 
771       PDF defines a standard date format, which closely follows that of
772       the international standard ASN.1 (Abstract Syntax Notation One),
773       defined in ISO/IEC 8824 (see the Bibliography). A date is a string
774       of the form
775 
776         (D:YYYYMMDDHHmmSSOHH'mm')
777 
778       where
779 
780         YYYY is the year
781         MM is the month
782         DD is the day (01-31)
783         HH is the hour (00-23)
784         mm is the minute (00-59)
785         SS is the second (00-59)
786         O is the relationship of local time to Universal Time (UT),
787           denoted by one of the characters +, -, or Z (see below)
788         HH followed by ' is the absolute value of the offset from UT
789           in hours (00-23)
790         mm followed by ' is the absolute value of the offset from UT
791           in minutes (00-59)
792 
793       The apostrophe character (') after HH and mm is part of the syntax.
794       All fields after the year are optional. (The prefix D:, although also
795       optional, is strongly recommended.) The default values for MM and DD
796       are both 01; all other numerical fields default to zero values.  A plus
797       sign (+) as the value of the O field signifies that local time is
798       later than UT, a minus sign (-) that local time is earlier than UT,
799       and the letter Z that local time is equal to UT. If no UT information
800       is specified, the relationship of the specified time to UT is
801       considered to be unknown. Whether or not the time zone is known, the
802       rest of the date should be specified in local time.
803 
804       For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard
805       Time, is represented by the string
806 
807         D:199812231952-08'00'
808   </blockquote>
809 
810   The main difficulty is get the time zone offset. strftime() does this in ISO
811   C99 (e.g. newer glibc) with %z, but we have to work with other systems (e.g.
812   Solaris 2.5).
813 */
814 
printcreationdate(void)815 void printcreationdate(void)
816 {
817     initstarttime();
818     pdf_printf("/CreationDate (%s)\n", start_time_str);
819 }
820 
printmoddate(void)821 void printmoddate(void)
822 {
823     initstarttime();
824     pdf_printf("/ModDate (%s)\n", start_time_str);
825 }
826 
827 #define DIGEST_SIZE 16
828 #define FILE_BUF_SIZE 1024
829 
getmd5sum(strnumber s,boolean file)830 void getmd5sum(strnumber s, boolean file)
831 {
832     md5_state_t state;
833     md5_byte_t digest[DIGEST_SIZE];
834     char outbuf[2 * DIGEST_SIZE + 1];
835     int len = 2 * DIGEST_SIZE;
836 
837     if (file) {
838         char file_buf[FILE_BUF_SIZE];
839         int read = 0;
840         FILE *f;
841 
842         char *file_name = kpse_find_tex(makecfilename(s));
843         if (file_name == NULL) {
844             return;             /* empty string */
845         }
846         /* in case of error the empty string is returned,
847            no need for xfopen that aborts on error.
848          */
849         f = fopen(file_name, FOPEN_RBIN_MODE);
850         if (f == NULL) {
851             xfree(file_name);
852             return;
853         }
854         recorder_record_input(file_name);
855         md5_init(&state);
856         while ((read = fread(&file_buf, sizeof(char), FILE_BUF_SIZE, f)) > 0) {
857             md5_append(&state, (const md5_byte_t *) file_buf, read);
858         }
859         md5_finish(&state, digest);
860         fclose(f);
861 
862         xfree(file_name);
863     } else {
864         /* s contains the data */
865         md5_init(&state);
866         md5_append(&state,
867                    (const md5_byte_t *) &strpool[strstart[s]],
868                    strstart[s + 1] - strstart[s]);
869         md5_finish(&state, digest);
870     }
871 
872     if (poolptr + len >= poolsize) {
873         /* error by str_toks that calls str_room(1) */
874         return;
875     }
876     convertStringToHexString((char *) digest, outbuf, DIGEST_SIZE);
877     memcpy(&strpool[poolptr], outbuf, len);
878     poolptr += len;
879 }
880 
881 #define DEFAULT_SUB_MATCH_COUNT 10
882 static int sub_match_count = DEFAULT_SUB_MATCH_COUNT;
883 static regmatch_t *pmatch = NULL;
884 static char *match_string = NULL;
885 
matchstrings(strnumber s,strnumber t,int subcount,boolean icase)886 void matchstrings(strnumber s, strnumber t, int subcount, boolean icase)
887 {
888     regex_t preg;
889     int cflags = REG_EXTENDED;
890     int eflags = 0;
891     int ret;
892     char *str;
893 
894     if (icase) {
895         cflags |= REG_ICASE;
896     }
897 
898     if (poolptr + 10 >= poolsize) {
899         poolptr = poolsize;
900         return;
901     }
902 
903     str = makecstring(s);
904     ret = regcomp(&preg, str, cflags);
905     if (ret != 0) {
906         size_t size = regerror(ret, &preg, NULL, 0);
907         str = xtalloc(size, char);
908         regerror(ret, &preg, str, size);
909         pdftex_warn("%s%s", "\\pdfmatch: ", str);
910         xfree(str);
911         strpool[poolptr++] = '-';
912         strpool[poolptr++] = '1';
913     } else {
914         str = makecstring(t);
915         sub_match_count = ((subcount < 0) ? DEFAULT_SUB_MATCH_COUNT : subcount);
916         xfree(pmatch);
917         if (sub_match_count > 0) {
918             pmatch = xtalloc(sub_match_count, regmatch_t);
919         }
920         ret = regexec(&preg, str, sub_match_count, pmatch, eflags);
921         xfree(match_string);
922         match_string = xstrdup(str);
923         strpool[poolptr++] = ((ret == 0) ? '1' : '0');
924     }
925 
926     regfree(&preg);
927 }
928 
getmatch(int i)929 void getmatch(int i)
930 {
931     int size, len = 0;          /* to avoid warning about uninitialized use of len */
932 
933     boolean found = i < sub_match_count
934         && match_string != NULL && pmatch[i].rm_so >= 0 && i >= 0;
935 
936     if (found) {
937         len = pmatch[i].rm_eo - pmatch[i].rm_so;
938         size = 20 + len;
939         /* 20: place for integer number and '->' */
940     } else {
941         size = 4;
942     }
943 
944     if (poolptr + size >= poolsize) {
945         poolptr = poolsize;
946         return;
947     }
948 
949     if (found) {
950         int j = snprintf((char *) &strpool[poolptr], 20, "%d",
951                          (int) pmatch[i].rm_so);
952         check_nprintf(j, 20);
953         poolptr += j;
954         strpool[poolptr++] = '-';
955         strpool[poolptr++] = '>';
956         memcpy(&strpool[poolptr], &match_string[pmatch[i].rm_so], len);
957         poolptr += len;
958         return;
959     }
960 
961     strpool[poolptr++] = '-';
962     strpool[poolptr++] = '1';
963     strpool[poolptr++] = '-';
964     strpool[poolptr++] = '>';
965 }
966 
967 /* function strips trailing zeros in string with numbers; */
968 /* leading zeros are not stripped (as in real life) */
stripzeros(char * a)969 char *stripzeros(char *a)
970 {
971     enum { NONUM, DOTNONUM, INT, DOT, LEADDOT, FRAC } s = NONUM, t = NONUM;
972     char *p, *q, *r;
973     for (p = q = r = a; *p != '\0';) {
974         switch (s) {
975         case NONUM:
976             if (*p >= '0' && *p <= '9')
977                 s = INT;
978             else if (*p == '.')
979                 s = LEADDOT;
980             break;
981         case DOTNONUM:
982             if (*p != '.' && (*p < '0' || *p > '9'))
983                 s = NONUM;
984             break;
985         case INT:
986             if (*p == '.')
987                 s = DOT;
988             else if (*p < '0' || *p > '9')
989                 s = NONUM;
990             break;
991         case DOT:
992         case LEADDOT:
993             if (*p >= '0' && *p <= '9')
994                 s = FRAC;
995             else if (*p == '.')
996                 s = DOTNONUM;
997             else
998                 s = NONUM;
999             break;
1000         case FRAC:
1001             if (*p == '.')
1002                 s = DOTNONUM;
1003             else if (*p < '0' || *p > '9')
1004                 s = NONUM;
1005             break;
1006         default:;
1007         }
1008         switch (s) {
1009         case DOT:
1010             r = q;
1011             break;
1012         case LEADDOT:
1013             r = q + 1;
1014             break;
1015         case FRAC:
1016             if (*p > '0')
1017                 r = q + 1;
1018             break;
1019         case NONUM:
1020             if ((t == FRAC || t == DOT) && r != a) {
1021                 q = r--;
1022                 if (*r == '.')  /* was a LEADDOT */
1023                     *r = '0';
1024                 r = a;
1025             }
1026             break;
1027         default:;
1028         }
1029         *q++ = *p++;
1030         t = s;
1031     }
1032     *q = '\0';
1033     return a;
1034 }
1035 
initversionstring(char ** versions)1036 void initversionstring(char **versions)
1037 {
1038     const_string fmt =
1039                     "Compiled with libpng %s; using libpng %s\n"
1040                     "Compiled with zlib %s; using zlib %s\n"
1041                     "Compiled with %s version %s\n";
1042     size_t len = strlen(fmt)
1043                     + strlen(PNG_LIBPNG_VER_STRING) + strlen(png_libpng_ver)
1044                     + strlen(ZLIB_VERSION) + strlen(zlib_version)
1045                     + strlen(xpdfString) + strlen(xpdfVersion)
1046                     + 1;
1047 
1048     /* len will be more than enough, because of the placeholder chars in fmt
1049        that get replaced by the arguments.  */
1050     *versions = xmalloc(len);
1051     sprintf(*versions, fmt,
1052                     PNG_LIBPNG_VER_STRING, png_libpng_ver,
1053                     ZLIB_VERSION, zlib_version, xpdfString, xpdfVersion);
1054 }
1055 
1056 
1057 /*************************************************/
1058 /* Color Stack and Matrix Transformation Support */
1059 /*************************************************/
1060 
1061 /*
1062     In the following array and especially stack data structures are used.
1063     They have the following properties:
1064     - They automatically grow dynamically.
1065     - The size never decreases.
1066     - The variable with name ending in "size" contains the number how many
1067       entries the data structure can hold.
1068     - The variable with name ending in "used" contains the number of
1069       actually used entries.
1070     - Memory of strings in stack entries must be allocated and
1071       freed if the stack is cleared.
1072 */
1073 
1074 /* Color Stack */
1075 
1076 #define STACK_INCREMENT 8
1077 #define MAX_COLORSTACKS 32768
1078 /* The colorstack number is stored in two bytes (info field of the node) */
1079 /* Condition (newcolorstack): MAX_COLORSTACKS mod STACK_INCREMENT = 0 */
1080 
1081 #define COLOR_DEFAULT "0 g 0 G"
1082 /* literal_modes, see pdftex.web */
1083 #define SET_ORIGIN 0
1084 #define DIRECT_PAGE 1
1085 #define DIRECT_ALWAYS 2
1086 
1087 /* remember shipout mode: page/form */
1088 static boolean page_mode;
1089 
1090 typedef struct {
1091     char **page_stack;
1092     char **form_stack;
1093     char *page_current;
1094     char *form_current;
1095     char *form_init;
1096     int page_size;
1097     int form_size;
1098     int page_used;
1099     int form_used;
1100     int literal_mode;
1101     boolean page_start;
1102 } colstack_type;
1103 
1104 static colstack_type *colstacks = NULL;
1105 static int colstacks_size = 0;
1106 static int colstacks_used = 0;
1107 
1108 /*
1109     Initialization is done, if the color stacks are used,
1110     init_colorstacks() is defined as macro to avoid unnecessary
1111     procedure calls.
1112 */
1113 #define init_colorstacks() if (colstacks_size == 0) colstacks_first_init();
colstacks_first_init(void)1114 static void colstacks_first_init(void)
1115 {
1116     colstacks_size = STACK_INCREMENT;
1117     colstacks = xtalloc(colstacks_size, colstack_type);
1118     colstacks_used = 1;
1119     colstacks[0].page_stack = NULL;
1120     colstacks[0].form_stack = NULL;
1121     colstacks[0].page_size = 0;
1122     colstacks[0].form_size = 0;
1123     colstacks[0].page_used = 0;
1124     colstacks[0].form_used = 0;
1125     colstacks[0].page_current = xstrdup(COLOR_DEFAULT);
1126     colstacks[0].form_current = xstrdup(COLOR_DEFAULT);
1127     colstacks[0].form_init = xstrdup(COLOR_DEFAULT);
1128     colstacks[0].literal_mode = DIRECT_ALWAYS;
1129     colstacks[0].page_start = true;
1130 }
1131 
colorstackused(void)1132 int colorstackused(void)
1133 {
1134     init_colorstacks();
1135     return colstacks_used;
1136 }
1137 
1138 /*
1139     newcolorstack()
1140     A new color stack is setup with the given parameters.
1141     The stack number is returned or -1 in case of error (no room).
1142 */
newcolorstack(integer s,integer literal_mode,boolean page_start)1143 int newcolorstack(integer s, integer literal_mode, boolean page_start)
1144 {
1145     colstack_type *colstack;
1146     int colstack_num;
1147     char *str;
1148 
1149     init_colorstacks();
1150 
1151     /* make room */
1152     if (colstacks_used == MAX_COLORSTACKS) {
1153         return -1;
1154     }
1155     if (colstacks_used == colstacks_size) {
1156         colstacks_size += STACK_INCREMENT;
1157         /* If (MAX_COLORSTACKS mod STACK_INCREMENT = 0) then we don't
1158            need to check the case that size overruns MAX_COLORSTACKS. */
1159         xretalloc(colstacks, colstacks_size, colstack_type);
1160     }
1161     /* claim new color stack */
1162     colstack_num = colstacks_used++;
1163     colstack = &colstacks[colstack_num];
1164     /* configure the new color stack */
1165     colstack->page_stack = NULL;
1166     colstack->form_stack = NULL;
1167     colstack->page_size = 0;
1168     colstack->page_used = 0;
1169     colstack->form_size = 0;
1170     colstack->form_used = 0;
1171     colstack->literal_mode = literal_mode;
1172     colstack->page_start = page_start;
1173     str = makecstring(s);
1174     if (*str == 0) {
1175         colstack->page_current = NULL;
1176         colstack->form_current = NULL;
1177         colstack->form_init = NULL;
1178     } else {
1179         colstack->page_current = xstrdup(str);
1180         colstack->form_current = xstrdup(str);
1181         colstack->form_init = xstrdup(str);
1182     }
1183     return colstack_num;
1184 }
1185 
1186 #define get_colstack(n) (&colstacks[n])
1187 
1188 /*
1189     Puts a string on top of the string pool and updates poolptr.
1190 */
put_cstring_on_strpool(poolpointer start,char * str)1191 static void put_cstring_on_strpool(poolpointer start, char *str)
1192 {
1193     size_t len;
1194 
1195     if (str == NULL || *str == 0) {
1196         return;
1197     }
1198 
1199     len = strlen(str);
1200     poolptr = start + len;
1201     if (poolptr >= poolsize) {
1202         poolptr = poolsize;
1203         /* error by str_toks that calls str_room(1) */
1204         return;
1205     }
1206     memcpy(&strpool[start], str, len);
1207 }
1208 
colorstackset(int colstack_no,integer s)1209 integer colorstackset(int colstack_no, integer s)
1210 {
1211     colstack_type *colstack = get_colstack(colstack_no);
1212 
1213     if (page_mode) {
1214         xfree(colstack->page_current);
1215         colstack->page_current = xstrdup(makecstring(s));
1216     } else {
1217         xfree(colstack->form_current);
1218         colstack->form_current = xstrdup(makecstring(s));
1219     }
1220     return colstack->literal_mode;
1221 }
1222 
colorstackcurrent(int colstack_no)1223 integer colorstackcurrent(int colstack_no)
1224 {
1225     colstack_type *colstack = get_colstack(colstack_no);
1226 
1227     if (page_mode) {
1228         put_cstring_on_strpool(poolptr, colstack->page_current);
1229     } else {
1230         put_cstring_on_strpool(poolptr, colstack->form_current);
1231     }
1232     return colstack->literal_mode;
1233 }
1234 
colorstackpush(int colstack_no,integer s)1235 integer colorstackpush(int colstack_no, integer s)
1236 {
1237     colstack_type *colstack = get_colstack(colstack_no);
1238     char *str;
1239 
1240     if (page_mode) {
1241         if (colstack->page_used == colstack->page_size) {
1242             colstack->page_size += STACK_INCREMENT;
1243             xretalloc(colstack->page_stack, colstack->page_size, char *);
1244         }
1245         colstack->page_stack[colstack->page_used++] = colstack->page_current;
1246         str = makecstring(s);
1247         if (*str == 0) {
1248             colstack->page_current = NULL;
1249         } else {
1250             colstack->page_current = xstrdup(str);
1251         }
1252     } else {
1253         if (colstack->form_used == colstack->form_size) {
1254             colstack->form_size += STACK_INCREMENT;
1255             xretalloc(colstack->form_stack, colstack->form_size, char *);
1256         }
1257         colstack->form_stack[colstack->form_used++] = colstack->form_current;
1258         str = makecstring(s);
1259         if (*str == 0) {
1260             colstack->form_current = NULL;
1261         } else {
1262             colstack->form_current = xstrdup(str);
1263         }
1264     }
1265     return colstack->literal_mode;
1266 }
1267 
colorstackpop(int colstack_no)1268 integer colorstackpop(int colstack_no)
1269 {
1270     colstack_type *colstack = get_colstack(colstack_no);
1271 
1272     if (page_mode) {
1273         if (colstack->page_used == 0) {
1274             pdftex_warn("pop empty color page stack %u",
1275                         (unsigned int) colstack_no);
1276             return colstack->literal_mode;
1277         }
1278         xfree(colstack->page_current);
1279         colstack->page_current = colstack->page_stack[--colstack->page_used];
1280         put_cstring_on_strpool(poolptr, colstack->page_current);
1281     } else {
1282         if (colstack->form_used == 0) {
1283             pdftex_warn("pop empty color form stack %u",
1284                         (unsigned int) colstack_no);
1285             return colstack->literal_mode;
1286         }
1287         xfree(colstack->form_current);
1288         colstack->form_current = colstack->form_stack[--colstack->form_used];
1289         put_cstring_on_strpool(poolptr, colstack->form_current);
1290     }
1291     return colstack->literal_mode;
1292 }
1293 
colorstackpagestart(void)1294 static void colorstackpagestart(void)
1295 {
1296     int i, j;
1297     colstack_type *colstack;
1298 
1299     if (page_mode) {
1300         /* see procedure pdf_out_colorstack_startpage */
1301         return;
1302     }
1303 
1304     for (i = 0; i < colstacks_used; i++) {
1305         colstack = &colstacks[i];
1306         for (j = 0; j < colstack->form_used; j++) {
1307             xfree(colstack->form_stack[j]);
1308         }
1309         colstack->form_used = 0;
1310         xfree(colstack->form_current);
1311         if (colstack->form_init == NULL) {
1312             colstack->form_current = NULL;
1313         } else {
1314             colstack->form_current = xstrdup(colstack->form_init);
1315         }
1316     }
1317 }
1318 
colorstackskippagestart(int colstack_no)1319 integer colorstackskippagestart(int colstack_no)
1320 {
1321     colstack_type *colstack = get_colstack(colstack_no);
1322 
1323     if (!colstack->page_start) {
1324         return 1;
1325     }
1326     if (colstack->page_current == NULL) {
1327         return 0;
1328     }
1329     if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) {
1330         return 2;
1331     }
1332     return 0;
1333 }
1334 
1335 
1336 /* stack for \pdfsetmatrix */
1337 
1338 typedef struct {
1339     double a;
1340     double b;
1341     double c;
1342     double d;
1343     double e;
1344     double f;
1345 } matrix_entry;
1346 static matrix_entry *matrix_stack = 0;
1347 static int matrix_stack_size = 0;
1348 static int matrix_stack_used = 0;
1349 
matrixused(void)1350 boolean matrixused(void)
1351 {
1352     return matrix_stack_used > 0;
1353 }
1354 
1355 /* stack for positions of \pdfsave */
1356 typedef struct {
1357     int pos_h;
1358     int pos_v;
1359     int matrix_stack;
1360 } pos_entry;
1361 static pos_entry *pos_stack = 0;        /* the stack */
1362 static int pos_stack_size = 0;  /* initially empty */
1363 static int pos_stack_used = 0;  /* used entries */
1364 
matrix_stack_room(void)1365 static void matrix_stack_room(void)
1366 {
1367     matrix_entry *new_stack;
1368 
1369     if (matrix_stack_used >= matrix_stack_size) {
1370         matrix_stack_size += STACK_INCREMENT;
1371         new_stack = xtalloc(matrix_stack_size, matrix_entry);
1372         memcpy((void *) new_stack, (void *) matrix_stack,
1373                matrix_stack_used * sizeof(matrix_entry));
1374         xfree(matrix_stack);
1375         matrix_stack = new_stack;
1376     }
1377 }
1378 
checkpdfsave(int cur_h,int cur_v)1379 void checkpdfsave(int cur_h, int cur_v)
1380 {
1381     pos_entry *new_stack;
1382 
1383     if (pos_stack_used >= pos_stack_size) {
1384         pos_stack_size += STACK_INCREMENT;
1385         new_stack = xtalloc(pos_stack_size, pos_entry);
1386         memcpy((void *) new_stack, (void *) pos_stack,
1387                pos_stack_used * sizeof(pos_entry));
1388         xfree(pos_stack);
1389         pos_stack = new_stack;
1390     }
1391     pos_stack[pos_stack_used].pos_h = cur_h;
1392     pos_stack[pos_stack_used].pos_v = cur_v;
1393     if (page_mode) {
1394         pos_stack[pos_stack_used].matrix_stack = matrix_stack_used;
1395     }
1396     pos_stack_used++;
1397 }
1398 
checkpdfrestore(int cur_h,int cur_v)1399 void checkpdfrestore(int cur_h, int cur_v)
1400 {
1401     int diff_h, diff_v;
1402     if (pos_stack_used == 0) {
1403         pdftex_warn("%s", "\\pdfrestore: missing \\pdfsave");
1404         return;
1405     }
1406     pos_stack_used--;
1407     diff_h = cur_h - pos_stack[pos_stack_used].pos_h;
1408     diff_v = cur_v - pos_stack[pos_stack_used].pos_v;
1409     if (diff_h != 0 || diff_v != 0) {
1410         pdftex_warn("Misplaced \\pdfrestore by (%usp, %usp)", diff_h, diff_v);
1411     }
1412     if (page_mode) {
1413         matrix_stack_used = pos_stack[pos_stack_used].matrix_stack;
1414     }
1415 }
1416 
pdfshipoutbegin(boolean shipping_page)1417 void pdfshipoutbegin(boolean shipping_page)
1418 {
1419     pos_stack_used = 0;         /* start with empty stack */
1420 
1421     page_mode = shipping_page;
1422     if (shipping_page) {
1423         colorstackpagestart();
1424     }
1425 }
1426 
pdfshipoutend(boolean shipping_page)1427 void pdfshipoutend(boolean shipping_page)
1428 {
1429     if (pos_stack_used > 0) {
1430         pdftex_fail("%u unmatched \\pdfsave after %s shipout",
1431                     (unsigned int) pos_stack_used,
1432                     ((shipping_page) ? "page" : "form"));
1433     }
1434 }
1435 
1436 /*
1437     \pdfsetmatrix{a b c d}
1438     e := cur_h
1439     f := cur_v
1440     M_top: current active matrix at the top of
1441            the matrix stack
1442 
1443     The origin of \pdfsetmatrix is the current point.
1444     The annotation coordinate system is the original
1445     page coordinate system. When pdfTeX calculates
1446     annotation rectangles it does not take into
1447     account this transformations, it uses the original
1448     coordinate system. To get the corrected values,
1449     first we go back to the origin, perform the
1450     transformation and go back:
1451 
1452     (  1   0  0 )   ( a b 0 )   ( 1 0 0 )
1453     (  0   1  0 ) x ( c d 0 ) x ( 0 1 0 ) x M_top
1454     ( -e  -f  1 )   ( 0 0 1 )   ( e f 1 )
1455 
1456     ( 1  0  0 )   (  a  b 0 )
1457   = ( 0  1  0 ) x (  c  d 0 ) x M_top
1458     ( e  f  1 )   ( -e -f 1 )
1459 
1460     ( a         b         0 )
1461   = ( c         d         0 ) x M_top
1462     ( e(1-a)-fc f(1-d)-eb 1 )
1463 
1464 */
1465 
pdfsetmatrix(poolpointer in,scaled cur_h,scaled cur_v)1466 integer pdfsetmatrix(poolpointer in, scaled cur_h, scaled cur_v)
1467 {
1468     /* Argument of \pdfsetmatrix starts with strpool[in] and ends
1469        before strpool[poolptr]. */
1470 
1471     matrix_entry x, *y, *z;
1472     char dummy;
1473 
1474     if (page_mode) {
1475         if (sscanf((const char *) &strpool[in], " %lf %lf %lf %lf %c",
1476                    &x.a, &x.b, &x.c, &x.d, &dummy) != 4) {
1477             return 0; /* failure */
1478         }
1479         /* calculate this transformation matrix */
1480         x.e = (double) cur_h *(1.0 - x.a) - (double) cur_v *x.c;
1481         x.f = (double) cur_v *(1.0 - x.d) - (double) cur_h *x.b;
1482         matrix_stack_room();
1483         z = &matrix_stack[matrix_stack_used];
1484         if (matrix_stack_used > 0) {
1485             y = &matrix_stack[matrix_stack_used - 1];
1486             z->a = x.a * y->a + x.b * y->c;
1487             z->b = x.a * y->b + x.b * y->d;
1488             z->c = x.c * y->a + x.d * y->c;
1489             z->d = x.c * y->b + x.d * y->d;
1490             z->e = x.e * y->a + x.f * y->c + y->e;
1491             z->f = x.e * y->b + x.f * y->d + y->f;
1492         } else {
1493             z->a = x.a;
1494             z->b = x.b;
1495             z->c = x.c;
1496             z->d = x.d;
1497             z->e = x.e;
1498             z->f = x.f;
1499         }
1500         matrix_stack_used++;
1501     }
1502     return 1; /* success */
1503 }
1504 
1505 /* Apply matrix to point (x,y)
1506 
1507                ( a b 0 )
1508    ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 )
1509                ( e f 1 )
1510 
1511    If \pdfsetmatrix wasn't used, then return the value unchanged.
1512 */
1513 
1514 /* Return valeus for matrix tranform functions */
1515 static scaled ret_llx;
1516 static scaled ret_lly;
1517 static scaled ret_urx;
1518 static scaled ret_ury;
1519 
getllx(void)1520 scaled getllx(void)
1521 {
1522     return ret_llx;
1523 }
1524 
getlly(void)1525 scaled getlly(void)
1526 {
1527     return ret_lly;
1528 }
1529 
geturx(void)1530 scaled geturx(void)
1531 {
1532     return ret_urx;
1533 }
1534 
getury(void)1535 scaled getury(void)
1536 {
1537     return ret_ury;
1538 }
1539 
1540 static int last_llx;
1541 static int last_lly;
1542 static int last_urx;
1543 static int last_ury;
1544 
1545 #define DO_ROUND(x)  ((x > 0) ? (x + .5) : (x - .5))
1546 #define DO_MIN(a, b) ((a < b) ? a : b)
1547 #define DO_MAX(a, b) ((a > b) ? a : b)
1548 
do_matrixtransform(scaled x,scaled y,scaled * retx,scaled * rety)1549 static void do_matrixtransform(scaled x, scaled y, scaled * retx, scaled * rety)
1550 {
1551     matrix_entry *m = &matrix_stack[matrix_stack_used - 1];
1552     double x_old = x;
1553     double y_old = y;
1554     double x_new = x_old * m->a + y_old * m->c + m->e;
1555     double y_new = x_old * m->b + y_old * m->d + m->f;
1556     *retx = (scaled) DO_ROUND(x_new);
1557     *rety = (scaled) DO_ROUND(y_new);
1558 }
1559 
matrixtransformrect(scaled llx,scaled lly,scaled urx,scaled ury)1560 void matrixtransformrect(scaled llx, scaled lly, scaled urx, scaled ury)
1561 {
1562     scaled x1, x2, x3, x4, y1, y2, y3, y4;
1563 
1564     if (page_mode && matrix_stack_used > 0) {
1565         last_llx = llx;
1566         last_lly = lly;
1567         last_urx = urx;
1568         last_ury = ury;
1569         do_matrixtransform(llx, lly, &x1, &y1);
1570         do_matrixtransform(llx, ury, &x2, &y2);
1571         do_matrixtransform(urx, lly, &x3, &y3);
1572         do_matrixtransform(urx, ury, &x4, &y4);
1573         ret_llx = DO_MIN(DO_MIN(x1, x2), DO_MIN(x3, x4));
1574         ret_lly = DO_MIN(DO_MIN(y1, y2), DO_MIN(y3, y4));
1575         ret_urx = DO_MAX(DO_MAX(x1, x2), DO_MAX(x3, x4));
1576         ret_ury = DO_MAX(DO_MAX(y1, y2), DO_MAX(y3, y4));
1577     } else {
1578         ret_llx = llx;
1579         ret_lly = lly;
1580         ret_urx = urx;
1581         ret_ury = ury;
1582     }
1583 }
1584 
matrixtransformpoint(scaled x,scaled y)1585 void matrixtransformpoint(scaled x, scaled y)
1586 {
1587     if (page_mode && matrix_stack_used > 0) {
1588         do_matrixtransform(x, y, &ret_llx, &ret_lly);
1589     } else {
1590         ret_llx = x;
1591         ret_lly = y;
1592     }
1593 }
1594 
matrixrecalculate(scaled urx)1595 void matrixrecalculate(scaled urx)
1596 {
1597     matrixtransformrect(last_llx, last_lly, urx, last_ury);
1598 }
1599 
allocvffnts(void)1600 void allocvffnts(void)
1601 {
1602     if (vf_e_fnts_array == NULL) {
1603         vf_e_fnts_array = vfefnts;
1604         vf_e_fnts_limit = fontmax;
1605         vf_e_fnts_ptr = vf_e_fnts_array;
1606         vf_i_fnts_array = vfifnts;
1607         vf_i_fnts_limit = fontmax;
1608         vf_i_fnts_ptr = vf_i_fnts_array;
1609     }
1610     alloc_array(vf_e_fnts, 1, fontmax);
1611     vf_e_fnts_ptr++;
1612     alloc_array(vf_i_fnts, 1, fontmax);
1613     vf_i_fnts_ptr++;
1614     if (vf_e_fnts_array != vfefnts) {
1615         vfefnts = vf_e_fnts_array;
1616         vfifnts = vf_i_fnts_array;
1617     }
1618 }
1619