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