ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/texlive/trunk/Build/source/texk/web2c/pdftexdir/utils.c
Revision: 57915
Committed: Thu Feb 25 19:22:25 2021 UTC (3 years, 6 months ago) by karl
Content type: text/x-c
File size: 45191 byte(s)
Log Message:
restore Build,TODO from r57911

File Contents

# Content
1 /*
2 Copyright 1996-2017 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 /* POPPLER_VERSION should be a proper version string */
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
72 integer fb_offset(void)
73 {
74 return fb_ptr - fb_array;
75 }
76
77 void fb_seek(integer offset)
78 {
79 fb_ptr = fb_array + offset;
80 }
81
82 void fb_putchar(eightbits b)
83 {
84 alloc_array(fb, 1, SMALL_ARRAY_SIZE);
85 *fb_ptr++ = b;
86 }
87
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
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
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
161 void pdf_newline(void)
162 {
163 if (pdflastbyte != '\n')
164 pdf_puts("\n");
165 }
166
167 __attribute__ ((format(printf, 1, 2)))
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
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)))
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. */
203 static void safe_print(const char *str)
204 {
205 const char *c;
206 for (c = str; *c; ++c)
207 print(*c);
208 }
209
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)))
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)))
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
275 void garbagewarning(void)
276 {
277 pdftex_warn("dangling objects discarded, no output file produced.");
278 removepdffile();
279 }
280
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
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
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
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
362 int xfflush(FILE * stream)
363 {
364 if (fflush(stream) != 0)
365 pdftex_fail("fflush() failed (%s)", strerror(errno));
366 return 0;
367 }
368
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
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
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
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
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 */
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 */
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 */
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 */
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 */
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 /* Compute the ID string as per PDF1.4 9.3:
674 <blockquote>
675 File identifers are defined by the optional ID entry in a PDF file's
676 trailer dictionary (see Section 3.4.4, "File Trailer"; see also
677 implementation note 105 in Appendix H). The value of this entry is an
678 array of two strings. The first string is a permanent identifier based
679 on the contents of the file at the time it was originally created, and
680 does not change when the file is incrementally updated. The second
681 string is a changing identifier based on the file's contents at the
682 time it was last updated. When a file is first written, both
683 identifiers are set to the same value. If both identifiers match when a
684 file reference is resolved, it is very likely that the correct file has
685 been found; if only the first identifier matches, then a different
686 version of the correct file has been found.
687 To help ensure the uniqueness of file identifiers, it is recommend
688 that they be computed using a message digest algorithm such as MD5
689 (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see
690 the Bibliography), using the following information (see implementation
691 note 106 in Appendix H):
692 - The current time
693 - A string representation of the file's location, usually a pathname
694 - The size of the file in bytes
695 - The values of all entries in the file's document information
696 dictionary (see Section 9.2.1, Document Information Dictionary )
697 </blockquote>
698 This stipulates only that the two IDs must be identical when the file is
699 created and that they should be reasonably unique. Since it's difficult
700 to get the file size at this point in the execution of pdfTeX, scanning
701 the info dict is also difficult, and any variability in the current
702 directory name leads to non-reproducible builds, we start with a
703 simpler implementation using just the current time and the file name.
704 */
705 void printID(strnumber filename)
706 {
707 md5_state_t state;
708 md5_byte_t digest[16];
709 char id[64];
710 char *file_name;
711 /* start md5 */
712 md5_init(&state);
713 /* get the time */
714 initstarttime();
715 md5_append(&state, (const md5_byte_t *) start_time_str, strlen(start_time_str));
716 /* get the file name */
717 file_name = makecstring(filename);
718 md5_append(&state, (const md5_byte_t *) file_name, strlen(file_name));
719 /* finish md5 */
720 md5_finish(&state, digest);
721 /* write the IDs */
722 convertStringToHexString((char *) digest, id, 16);
723 pdf_printf("/ID [<%s> <%s>]", id, id);
724 }
725
726 void printIDalt(integer toks)
727 {
728 md5_state_t state;
729 md5_byte_t digest[16];
730 char id[64];
731 char *s = makecstring(tokenstostring(toks));
732 flushstr(lasttokensstring);
733 if (strlen(s) == 0)
734 return;
735 md5_init(&state);
736 md5_append(&state, (const md5_byte_t *) s, strlen(s));
737 md5_finish(&state, digest);
738 convertStringToHexString((char *) digest, id, 16);
739 pdf_printf("/ID [<%s> <%s>]", id, id);
740 }
741
742
743 /* Print the /CreationDate entry.
744
745 PDF Reference, third edition says about the expected date format:
746 <blockquote>
747 3.8.2 Dates
748
749 PDF defines a standard date format, which closely follows that of
750 the international standard ASN.1 (Abstract Syntax Notation One),
751 defined in ISO/IEC 8824 (see the Bibliography). A date is a string
752 of the form
753
754 (D:YYYYMMDDHHmmSSOHH'mm')
755
756 where
757
758 YYYY is the year
759 MM is the month
760 DD is the day (01-31)
761 HH is the hour (00-23)
762 mm is the minute (00-59)
763 SS is the second (00-59)
764 O is the relationship of local time to Universal Time (UT),
765 denoted by one of the characters +, -, or Z (see below)
766 HH followed by ' is the absolute value of the offset from UT
767 in hours (00-23)
768 mm followed by ' is the absolute value of the offset from UT
769 in minutes (00-59)
770
771 The apostrophe character (') after HH and mm is part of the syntax.
772 All fields after the year are optional. (The prefix D:, although also
773 optional, is strongly recommended.) The default values for MM and DD
774 are both 01; all other numerical fields default to zero values. A plus
775 sign (+) as the value of the O field signifies that local time is
776 later than UT, a minus sign (-) that local time is earlier than UT,
777 and the letter Z that local time is equal to UT. If no UT information
778 is specified, the relationship of the specified time to UT is
779 considered to be unknown. Whether or not the time zone is known, the
780 rest of the date should be specified in local time.
781
782 For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard
783 Time, is represented by the string
784
785 D:199812231952-08'00'
786 </blockquote>
787
788 The main difficulty is get the time zone offset. strftime() does this in ISO
789 C99 (e.g. newer glibc) with %z, but we have to work with other systems (e.g.
790 Solaris 2.5).
791 */
792
793 void printcreationdate(void)
794 {
795 initstarttime();
796 pdf_printf("/CreationDate (%s)\n", start_time_str);
797 }
798
799 void printmoddate(void)
800 {
801 initstarttime();
802 pdf_printf("/ModDate (%s)\n", start_time_str);
803 }
804
805
806 #define DEFAULT_SUB_MATCH_COUNT 10
807 static int sub_match_count = DEFAULT_SUB_MATCH_COUNT;
808 static regmatch_t *pmatch = NULL;
809 static char *match_string = NULL;
810 static int last_match_succeeded = 0;
811
812 /* Implements \pdfmatch */
813 void
814 matchstrings(strnumber s, strnumber t, int subcount, boolean icase)
815 {
816 regex_t preg;
817 int cflags = REG_EXTENDED;
818 int eflags = 0;
819 int ret;
820 char *str;
821
822 if (icase) {
823 cflags |= REG_ICASE;
824 }
825
826 if (poolptr + 10 >= poolsize) {
827 poolptr = poolsize;
828 return;
829 }
830
831 str = makecstring(s);
832 ret = regcomp(&preg, str, cflags);
833 if (ret != 0) {
834 size_t size = regerror(ret, &preg, NULL, 0);
835 str = xtalloc(size, char);
836 regerror(ret, &preg, str, size);
837 pdftex_warn("%s%s", "\\pdfmatch: ", str);
838 xfree(str);
839 strpool[poolptr++] = '-';
840 strpool[poolptr++] = '1';
841 } else {
842 str = makecstring(t);
843 sub_match_count = ((subcount < 0) ? DEFAULT_SUB_MATCH_COUNT : subcount);
844 xfree(pmatch);
845 if (sub_match_count > 0) {
846 pmatch = xtalloc(sub_match_count, regmatch_t);
847 }
848 ret = regexec(&preg, str, sub_match_count, pmatch, eflags);
849
850 xfree(match_string);
851 match_string = xstrdup(str); /* save searched-in string, used below */
852 last_match_succeeded = ret == 0; /* save whether match succeeded */
853 strpool[poolptr++] = ((ret == 0) ? '1' : '0'); /* in string pool too */
854 }
855
856 regfree(&preg);
857 }
858
859 /* Implements \pdflastmatch */
860
861 void
862 getmatch(int i)
863 {
864 int size;
865 int len = 0; /* avoid spurious uninitialized warning */
866
867 boolean found
868 = i >= 0 /* should always be so due to pdftex.web */
869 && i < sub_match_count /* if >subcount, not found by definition */
870 && match_string != NULL /* first call, and just in case */
871 && last_match_succeeded /* if no match, not found */
872 && pmatch[i].rm_so >= 0 /* if no starting position, not found */
873 && pmatch[i].rm_eo >= pmatch[i].rm_so; /* just in case */
874
875 if (found) {
876 len = pmatch[i].rm_eo - pmatch[i].rm_so;
877 size = 20 + len;
878 /* 20: place for integer number and '->' */
879 } else {
880 size = 4;
881 }
882
883 if (poolptr + size >= poolsize) {
884 poolptr = poolsize;
885 return;
886 }
887
888 if (found) {
889 int j = snprintf((char *) &strpool[poolptr], 20, "%d",
890 (int) pmatch[i].rm_so);
891 check_nprintf(j, 20);
892 poolptr += j;
893 strpool[poolptr++] = '-';
894 strpool[poolptr++] = '>';
895 memcpy(&strpool[poolptr], &match_string[pmatch[i].rm_so], len);
896 poolptr += len;
897 return;
898 }
899
900 strpool[poolptr++] = '-';
901 strpool[poolptr++] = '1';
902 strpool[poolptr++] = '-';
903 strpool[poolptr++] = '>';
904 }
905
906
907 /* function strips trailing zeros in string with numbers; */
908 /* leading zeros are not stripped (as in real life) */
909 char *stripzeros(char *a)
910 {
911 enum { NONUM, DOTNONUM, INT, DOT, LEADDOT, FRAC } s = NONUM, t = NONUM;
912 char *p, *q, *r;
913 for (p = q = r = a; *p != '\0';) {
914 switch (s) {
915 case NONUM:
916 if (*p >= '0' && *p <= '9')
917 s = INT;
918 else if (*p == '.')
919 s = LEADDOT;
920 break;
921 case DOTNONUM:
922 if (*p != '.' && (*p < '0' || *p > '9'))
923 s = NONUM;
924 break;
925 case INT:
926 if (*p == '.')
927 s = DOT;
928 else if (*p < '0' || *p > '9')
929 s = NONUM;
930 break;
931 case DOT:
932 case LEADDOT:
933 if (*p >= '0' && *p <= '9')
934 s = FRAC;
935 else if (*p == '.')
936 s = DOTNONUM;
937 else
938 s = NONUM;
939 break;
940 case FRAC:
941 if (*p == '.')
942 s = DOTNONUM;
943 else if (*p < '0' || *p > '9')
944 s = NONUM;
945 break;
946 default:;
947 }
948 switch (s) {
949 case DOT:
950 r = q;
951 break;
952 case LEADDOT:
953 r = q + 1;
954 break;
955 case FRAC:
956 if (*p > '0')
957 r = q + 1;
958 break;
959 case NONUM:
960 if ((t == FRAC || t == DOT) && r != a) {
961 q = r--;
962 if (*r == '.') /* was a LEADDOT */
963 *r = '0';
964 r = a;
965 }
966 break;
967 default:;
968 }
969 *q++ = *p++;
970 t = s;
971 }
972 *q = '\0';
973 return a;
974 }
975
976 void initversionstring(char **versions)
977 {
978 const_string fmt =
979 "Compiled with libpng %s; using libpng %s\n"
980 "Compiled with zlib %s; using zlib %s\n"
981 "Compiled with %s version %s\n";
982 size_t len = strlen(fmt)
983 + strlen(PNG_LIBPNG_VER_STRING) + strlen(png_libpng_ver)
984 + strlen(ZLIB_VERSION) + strlen(zlib_version)
985 + strlen(xpdfString) + strlen(xpdfVersion)
986 + 1;
987
988 /* len will be more than enough, because of the placeholder chars in fmt
989 that get replaced by the arguments. */
990 *versions = xmalloc(len);
991 sprintf(*versions, fmt,
992 PNG_LIBPNG_VER_STRING, png_libpng_ver,
993 ZLIB_VERSION, zlib_version, xpdfString, xpdfVersion);
994 }
995
996
997 /*************************************************/
998 /* Color Stack and Matrix Transformation Support */
999 /*************************************************/
1000
1001 /*
1002 In the following array and especially stack data structures are used.
1003 They have the following properties:
1004 - They automatically grow dynamically.
1005 - The size never decreases.
1006 - The variable with name ending in "size" contains the number how many
1007 entries the data structure can hold.
1008 - The variable with name ending in "used" contains the number of
1009 actually used entries.
1010 - Memory of strings in stack entries must be allocated and
1011 freed if the stack is cleared.
1012 */
1013
1014 /* Color Stack */
1015
1016 #define STACK_INCREMENT 8
1017 #define MAX_COLORSTACKS 32768
1018 /* The colorstack number is stored in two bytes (info field of the node) */
1019 /* Condition (newcolorstack): MAX_COLORSTACKS mod STACK_INCREMENT = 0 */
1020
1021 #define COLOR_DEFAULT "0 g 0 G"
1022 /* literal_modes, see pdftex.web */
1023 #define SET_ORIGIN 0
1024 #define DIRECT_PAGE 1
1025 #define DIRECT_ALWAYS 2
1026
1027 /* remember shipout mode: page/form */
1028 static boolean page_mode;
1029
1030 typedef struct {
1031 char **page_stack;
1032 char **form_stack;
1033 char *page_current;
1034 char *form_current;
1035 char *form_init;
1036 int page_size;
1037 int form_size;
1038 int page_used;
1039 int form_used;
1040 int literal_mode;
1041 boolean page_start;
1042 } colstack_type;
1043
1044 static colstack_type *colstacks = NULL;
1045 static int colstacks_size = 0;
1046 static int colstacks_used = 0;
1047
1048 /*
1049 Initialization is done, if the color stacks are used,
1050 init_colorstacks() is defined as macro to avoid unnecessary
1051 procedure calls.
1052 */
1053 #define init_colorstacks() if (colstacks_size == 0) colstacks_first_init();
1054 static void colstacks_first_init(void)
1055 {
1056 colstacks_size = STACK_INCREMENT;
1057 colstacks = xtalloc(colstacks_size, colstack_type);
1058 colstacks_used = 1;
1059 colstacks[0].page_stack = NULL;
1060 colstacks[0].form_stack = NULL;
1061 colstacks[0].page_size = 0;
1062 colstacks[0].form_size = 0;
1063 colstacks[0].page_used = 0;
1064 colstacks[0].form_used = 0;
1065 colstacks[0].page_current = xstrdup(COLOR_DEFAULT);
1066 colstacks[0].form_current = xstrdup(COLOR_DEFAULT);
1067 colstacks[0].form_init = xstrdup(COLOR_DEFAULT);
1068 colstacks[0].literal_mode = DIRECT_ALWAYS;
1069 colstacks[0].page_start = true;
1070 }
1071
1072 int colorstackused(void)
1073 {
1074 init_colorstacks();
1075 return colstacks_used;
1076 }
1077
1078 /*
1079 newcolorstack()
1080 A new color stack is setup with the given parameters.
1081 The stack number is returned or -1 in case of error (no room).
1082 */
1083 int newcolorstack(integer s, integer literal_mode, boolean page_start)
1084 {
1085 colstack_type *colstack;
1086 int colstack_num;
1087 char *str;
1088
1089 init_colorstacks();
1090
1091 /* make room */
1092 if (colstacks_used == MAX_COLORSTACKS) {
1093 return -1;
1094 }
1095 if (colstacks_used == colstacks_size) {
1096 colstacks_size += STACK_INCREMENT;
1097 /* If (MAX_COLORSTACKS mod STACK_INCREMENT = 0) then we don't
1098 need to check the case that size overruns MAX_COLORSTACKS. */
1099 xretalloc(colstacks, colstacks_size, colstack_type);
1100 }
1101 /* claim new color stack */
1102 colstack_num = colstacks_used++;
1103 colstack = &colstacks[colstack_num];
1104 /* configure the new color stack */
1105 colstack->page_stack = NULL;
1106 colstack->form_stack = NULL;
1107 colstack->page_size = 0;
1108 colstack->page_used = 0;
1109 colstack->form_size = 0;
1110 colstack->form_used = 0;
1111 colstack->literal_mode = literal_mode;
1112 colstack->page_start = page_start;
1113 str = makecstring(s);
1114 if (*str == 0) {
1115 colstack->page_current = NULL;
1116 colstack->form_current = NULL;
1117 colstack->form_init = NULL;
1118 } else {
1119 colstack->page_current = xstrdup(str);
1120 colstack->form_current = xstrdup(str);
1121 colstack->form_init = xstrdup(str);
1122 }
1123 return colstack_num;
1124 }
1125
1126 #define get_colstack(n) (&colstacks[n])
1127
1128 /*
1129 Puts a string on top of the string pool and updates poolptr.
1130 */
1131 static void put_cstring_on_strpool(poolpointer start, char *str)
1132 {
1133 size_t len;
1134
1135 if (str == NULL || *str == 0) {
1136 return;
1137 }
1138
1139 len = strlen(str);
1140 poolptr = start + len;
1141 if (poolptr >= poolsize) {
1142 poolptr = poolsize;
1143 /* error by str_toks that calls str_room(1) */
1144 return;
1145 }
1146 memcpy(&strpool[start], str, len);
1147 }
1148
1149 integer colorstackset(int colstack_no, integer s)
1150 {
1151 colstack_type *colstack = get_colstack(colstack_no);
1152
1153 if (page_mode) {
1154 xfree(colstack->page_current);
1155 colstack->page_current = xstrdup(makecstring(s));
1156 } else {
1157 xfree(colstack->form_current);
1158 colstack->form_current = xstrdup(makecstring(s));
1159 }
1160 return colstack->literal_mode;
1161 }
1162
1163 integer colorstackcurrent(int colstack_no)
1164 {
1165 colstack_type *colstack = get_colstack(colstack_no);
1166
1167 if (page_mode) {
1168 put_cstring_on_strpool(poolptr, colstack->page_current);
1169 } else {
1170 put_cstring_on_strpool(poolptr, colstack->form_current);
1171 }
1172 return colstack->literal_mode;
1173 }
1174
1175 integer colorstackpush(int colstack_no, integer s)
1176 {
1177 colstack_type *colstack = get_colstack(colstack_no);
1178 char *str;
1179
1180 if (page_mode) {
1181 if (colstack->page_used == colstack->page_size) {
1182 colstack->page_size += STACK_INCREMENT;
1183 xretalloc(colstack->page_stack, colstack->page_size, char *);
1184 }
1185 colstack->page_stack[colstack->page_used++] = colstack->page_current;
1186 str = makecstring(s);
1187 if (*str == 0) {
1188 colstack->page_current = NULL;
1189 } else {
1190 colstack->page_current = xstrdup(str);
1191 }
1192 } else {
1193 if (colstack->form_used == colstack->form_size) {
1194 colstack->form_size += STACK_INCREMENT;
1195 xretalloc(colstack->form_stack, colstack->form_size, char *);
1196 }
1197 colstack->form_stack[colstack->form_used++] = colstack->form_current;
1198 str = makecstring(s);
1199 if (*str == 0) {
1200 colstack->form_current = NULL;
1201 } else {
1202 colstack->form_current = xstrdup(str);
1203 }
1204 }
1205 return colstack->literal_mode;
1206 }
1207
1208 integer colorstackpop(int colstack_no)
1209 {
1210 colstack_type *colstack = get_colstack(colstack_no);
1211
1212 if (page_mode) {
1213 if (colstack->page_used == 0) {
1214 pdftex_warn("pop empty color page stack %u",
1215 (unsigned int) colstack_no);
1216 return colstack->literal_mode;
1217 }
1218 xfree(colstack->page_current);
1219 colstack->page_current = colstack->page_stack[--colstack->page_used];
1220 put_cstring_on_strpool(poolptr, colstack->page_current);
1221 } else {
1222 if (colstack->form_used == 0) {
1223 pdftex_warn("pop empty color form stack %u",
1224 (unsigned int) colstack_no);
1225 return colstack->literal_mode;
1226 }
1227 xfree(colstack->form_current);
1228 colstack->form_current = colstack->form_stack[--colstack->form_used];
1229 put_cstring_on_strpool(poolptr, colstack->form_current);
1230 }
1231 return colstack->literal_mode;
1232 }
1233
1234 static void colorstackpagestart(void)
1235 {
1236 int i, j;
1237 colstack_type *colstack;
1238
1239 if (page_mode) {
1240 /* see procedure pdf_out_colorstack_startpage */
1241 return;
1242 }
1243
1244 for (i = 0; i < colstacks_used; i++) {
1245 colstack = &colstacks[i];
1246 for (j = 0; j < colstack->form_used; j++) {
1247 xfree(colstack->form_stack[j]);
1248 }
1249 colstack->form_used = 0;
1250 xfree(colstack->form_current);
1251 if (colstack->form_init == NULL) {
1252 colstack->form_current = NULL;
1253 } else {
1254 colstack->form_current = xstrdup(colstack->form_init);
1255 }
1256 }
1257 }
1258
1259 integer colorstackskippagestart(int colstack_no)
1260 {
1261 colstack_type *colstack = get_colstack(colstack_no);
1262
1263 if (!colstack->page_start) {
1264 return 1;
1265 }
1266 if (colstack->page_current == NULL) {
1267 return 0;
1268 }
1269 if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) {
1270 return 2;
1271 }
1272 return 0;
1273 }
1274
1275
1276 /* stack for \pdfsetmatrix */
1277
1278 typedef struct {
1279 double a;
1280 double b;
1281 double c;
1282 double d;
1283 double e;
1284 double f;
1285 } matrix_entry;
1286 static matrix_entry *matrix_stack = 0;
1287 static int matrix_stack_size = 0;
1288 static int matrix_stack_used = 0;
1289
1290 boolean matrixused(void)
1291 {
1292 return matrix_stack_used > 0;
1293 }
1294
1295 /* stack for positions of \pdfsave */
1296 typedef struct {
1297 int pos_h;
1298 int pos_v;
1299 int matrix_stack;
1300 } pos_entry;
1301 static pos_entry *pos_stack = 0; /* the stack */
1302 static int pos_stack_size = 0; /* initially empty */
1303 static int pos_stack_used = 0; /* used entries */
1304
1305 static void matrix_stack_room(void)
1306 {
1307 matrix_entry *new_stack;
1308
1309 if (matrix_stack_used >= matrix_stack_size) {
1310 matrix_stack_size += STACK_INCREMENT;
1311 new_stack = xtalloc(matrix_stack_size, matrix_entry);
1312 memcpy((void *) new_stack, (void *) matrix_stack,
1313 matrix_stack_used * sizeof(matrix_entry));
1314 xfree(matrix_stack);
1315 matrix_stack = new_stack;
1316 }
1317 }
1318
1319 void checkpdfsave(int cur_h, int cur_v)
1320 {
1321 pos_entry *new_stack;
1322
1323 if (pos_stack_used >= pos_stack_size) {
1324 pos_stack_size += STACK_INCREMENT;
1325 new_stack = xtalloc(pos_stack_size, pos_entry);
1326 memcpy((void *) new_stack, (void *) pos_stack,
1327 pos_stack_used * sizeof(pos_entry));
1328 xfree(pos_stack);
1329 pos_stack = new_stack;
1330 }
1331 pos_stack[pos_stack_used].pos_h = cur_h;
1332 pos_stack[pos_stack_used].pos_v = cur_v;
1333 if (page_mode) {
1334 pos_stack[pos_stack_used].matrix_stack = matrix_stack_used;
1335 }
1336 pos_stack_used++;
1337 }
1338
1339 void checkpdfrestore(int cur_h, int cur_v)
1340 {
1341 int diff_h, diff_v;
1342 if (pos_stack_used == 0) {
1343 pdftex_warn("%s", "\\pdfrestore: missing \\pdfsave");
1344 return;
1345 }
1346 pos_stack_used--;
1347 diff_h = cur_h - pos_stack[pos_stack_used].pos_h;
1348 diff_v = cur_v - pos_stack[pos_stack_used].pos_v;
1349 if (diff_h != 0 || diff_v != 0) {
1350 pdftex_warn("Misplaced \\pdfrestore by (%usp, %usp)", diff_h, diff_v);
1351 }
1352 if (page_mode) {
1353 matrix_stack_used = pos_stack[pos_stack_used].matrix_stack;
1354 }
1355 }
1356
1357 void pdfshipoutbegin(boolean shipping_page)
1358 {
1359 pos_stack_used = 0; /* start with empty stack */
1360
1361 page_mode = shipping_page;
1362 if (shipping_page) {
1363 colorstackpagestart();
1364 }
1365 }
1366
1367 void pdfshipoutend(boolean shipping_page)
1368 {
1369 if (pos_stack_used > 0) {
1370 pdftex_fail("%u unmatched \\pdfsave after %s shipout",
1371 (unsigned int) pos_stack_used,
1372 ((shipping_page) ? "page" : "form"));
1373 }
1374 }
1375
1376 /*
1377 \pdfsetmatrix{a b c d}
1378 e := cur_h
1379 f := cur_v
1380 M_top: current active matrix at the top of
1381 the matrix stack
1382
1383 The origin of \pdfsetmatrix is the current point.
1384 The annotation coordinate system is the original
1385 page coordinate system. When pdfTeX calculates
1386 annotation rectangles it does not take into
1387 account this transformations, it uses the original
1388 coordinate system. To get the corrected values,
1389 first we go back to the origin, perform the
1390 transformation and go back:
1391
1392 ( 1 0 0 ) ( a b 0 ) ( 1 0 0 )
1393 ( 0 1 0 ) x ( c d 0 ) x ( 0 1 0 ) x M_top
1394 ( -e -f 1 ) ( 0 0 1 ) ( e f 1 )
1395
1396 ( 1 0 0 ) ( a b 0 )
1397 = ( 0 1 0 ) x ( c d 0 ) x M_top
1398 ( e f 1 ) ( -e -f 1 )
1399
1400 ( a b 0 )
1401 = ( c d 0 ) x M_top
1402 ( e(1-a)-fc f(1-d)-eb 1 )
1403
1404 */
1405
1406 integer pdfsetmatrix(poolpointer in, scaled cur_h, scaled cur_v)
1407 {
1408 /* Argument of \pdfsetmatrix starts with strpool[in] and ends
1409 before strpool[poolptr]. */
1410
1411 matrix_entry x, *y, *z;
1412 char dummy;
1413
1414 if (page_mode) {
1415 if (sscanf((const char *) &strpool[in], " %lf %lf %lf %lf %c",
1416 &x.a, &x.b, &x.c, &x.d, &dummy) != 4) {
1417 return 0; /* failure */
1418 }
1419 /* calculate this transformation matrix */
1420 x.e = (double) cur_h *(1.0 - x.a) - (double) cur_v *x.c;
1421 x.f = (double) cur_v *(1.0 - x.d) - (double) cur_h *x.b;
1422 matrix_stack_room();
1423 z = &matrix_stack[matrix_stack_used];
1424 if (matrix_stack_used > 0) {
1425 y = &matrix_stack[matrix_stack_used - 1];
1426 z->a = x.a * y->a + x.b * y->c;
1427 z->b = x.a * y->b + x.b * y->d;
1428 z->c = x.c * y->a + x.d * y->c;
1429 z->d = x.c * y->b + x.d * y->d;
1430 z->e = x.e * y->a + x.f * y->c + y->e;
1431 z->f = x.e * y->b + x.f * y->d + y->f;
1432 } else {
1433 z->a = x.a;
1434 z->b = x.b;
1435 z->c = x.c;
1436 z->d = x.d;
1437 z->e = x.e;
1438 z->f = x.f;
1439 }
1440 matrix_stack_used++;
1441 }
1442 return 1; /* success */
1443 }
1444
1445 /* Apply matrix to point (x,y)
1446
1447 ( a b 0 )
1448 ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 )
1449 ( e f 1 )
1450
1451 If \pdfsetmatrix wasn't used, then return the value unchanged.
1452 */
1453
1454 /* Return valeus for matrix tranform functions */
1455 static scaled ret_llx;
1456 static scaled ret_lly;
1457 static scaled ret_urx;
1458 static scaled ret_ury;
1459
1460 scaled getllx(void)
1461 {
1462 return ret_llx;
1463 }
1464
1465 scaled getlly(void)
1466 {
1467 return ret_lly;
1468 }
1469
1470 scaled geturx(void)
1471 {
1472 return ret_urx;
1473 }
1474
1475 scaled getury(void)
1476 {
1477 return ret_ury;
1478 }
1479
1480 static int last_llx;
1481 static int last_lly;
1482 static int last_urx;
1483 static int last_ury;
1484
1485 #define DO_ROUND(x) ((x > 0) ? (x + .5) : (x - .5))
1486 #define DO_MIN(a, b) ((a < b) ? a : b)
1487 #define DO_MAX(a, b) ((a > b) ? a : b)
1488
1489 static void do_matrixtransform(scaled x, scaled y, scaled * retx, scaled * rety)
1490 {
1491 matrix_entry *m = &matrix_stack[matrix_stack_used - 1];
1492 double x_old = x;
1493 double y_old = y;
1494 double x_new = x_old * m->a + y_old * m->c + m->e;
1495 double y_new = x_old * m->b + y_old * m->d + m->f;
1496 *retx = (scaled) DO_ROUND(x_new);
1497 *rety = (scaled) DO_ROUND(y_new);
1498 }
1499
1500 void matrixtransformrect(scaled llx, scaled lly, scaled urx, scaled ury)
1501 {
1502 scaled x1, x2, x3, x4, y1, y2, y3, y4;
1503
1504 if (page_mode && matrix_stack_used > 0) {
1505 last_llx = llx;
1506 last_lly = lly;
1507 last_urx = urx;
1508 last_ury = ury;
1509 do_matrixtransform(llx, lly, &x1, &y1);
1510 do_matrixtransform(llx, ury, &x2, &y2);
1511 do_matrixtransform(urx, lly, &x3, &y3);
1512 do_matrixtransform(urx, ury, &x4, &y4);
1513 ret_llx = DO_MIN(DO_MIN(x1, x2), DO_MIN(x3, x4));
1514 ret_lly = DO_MIN(DO_MIN(y1, y2), DO_MIN(y3, y4));
1515 ret_urx = DO_MAX(DO_MAX(x1, x2), DO_MAX(x3, x4));
1516 ret_ury = DO_MAX(DO_MAX(y1, y2), DO_MAX(y3, y4));
1517 } else {
1518 ret_llx = llx;
1519 ret_lly = lly;
1520 ret_urx = urx;
1521 ret_ury = ury;
1522 }
1523 }
1524
1525 void matrixtransformpoint(scaled x, scaled y)
1526 {
1527 if (page_mode && matrix_stack_used > 0) {
1528 do_matrixtransform(x, y, &ret_llx, &ret_lly);
1529 } else {
1530 ret_llx = x;
1531 ret_lly = y;
1532 }
1533 }
1534
1535 void matrixrecalculate(scaled urx)
1536 {
1537 matrixtransformrect(last_llx, last_lly, urx, last_ury);
1538 }
1539
1540 void allocvffnts(void)
1541 {
1542 if (vf_e_fnts_array == NULL) {
1543 vf_e_fnts_array = vfefnts;
1544 vf_e_fnts_limit = fontmax;
1545 vf_e_fnts_ptr = vf_e_fnts_array;
1546 vf_i_fnts_array = vfifnts;
1547 vf_i_fnts_limit = fontmax;
1548 vf_i_fnts_ptr = vf_i_fnts_array;
1549 }
1550 alloc_array(vf_e_fnts, 1, fontmax);
1551 vf_e_fnts_ptr++;
1552 alloc_array(vf_i_fnts, 1, fontmax);
1553 vf_i_fnts_ptr++;
1554 if (vf_e_fnts_array != vfefnts) {
1555 vfefnts = vf_e_fnts_array;
1556 vfifnts = vf_i_fnts_array;
1557 }
1558 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Date Revision Author HeadUR