summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/pdftexdir/utils.c
diff options
context:
space:
mode:
authorMartin Schröder <martin@oneiros.de>2006-12-26 23:37:34 +0000
committerMartin Schröder <martin@oneiros.de>2006-12-26 23:37:34 +0000
commit812aa90acbef4930ae356ab194f3f2a8f573f6e4 (patch)
treea1b8b3d895238994c60580df9e6f0619b2034923 /Build/source/texk/web2c/pdftexdir/utils.c
parente3bba99884ce591c9485122e96fff7071fc7c112 (diff)
Import pdftex 1.40-rc4, which also changes the signature of
print_version_and_exit, and adds a new library (libs/obsdcompat). git-svn-id: svn://tug.org/texlive/trunk@2959 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir/utils.c')
-rw-r--r--Build/source/texk/web2c/pdftexdir/utils.c1333
1 files changed, 1014 insertions, 319 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/utils.c b/Build/source/texk/web2c/pdftexdir/utils.c
index c1be283ba2e..351af9a9045 100644
--- a/Build/source/texk/web2c/pdftexdir/utils.c
+++ b/Build/source/texk/web2c/pdftexdir/utils.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org>
+Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org>
This file is part of pdfTeX.
@@ -17,41 +17,58 @@ You should have received a copy of the GNU General Public License
along with pdfTeX; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#25 $
+$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#24 $
*/
-#include "sys/types.h"
-#include "regex.h"
-#include "ptexlib.h"
-#include "zlib.h"
-#include "md5.h"
-#include <kpathsea/c-vararg.h>
+#include "openbsd-compat.h"
+#ifdef HAVE_ASPRINTF /* asprintf is not defined in openbsd-compat.h, but in stdio.h */
+# include <stdio.h>
+#endif
+#include <sys/types.h>
+#include <sysexits.h>
+#include <regex.h>
#include <kpathsea/c-proto.h>
#include <kpathsea/c-stat.h>
#include <kpathsea/c-fopen.h>
+#include <string.h>
#include <time.h>
+#include <float.h> /* for DBL_EPSILON */
+#include "md5.h"
+#include "zlib.h"
+#include "ptexlib.h"
+#include "png.h"
+#include "xpdf/config.h" /* just to get the xpdf version */
-static const char perforce_id[] =
- "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#25 $";
+#define check_nprintf(size_get, size_want) \
+ if ((unsigned)(size_get) >= (unsigned)(size_want)) \
+ pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
char *cur_file_name = NULL;
strnumber last_tex_string;
static char print_buf[PRINTF_BUF_SIZE];
static char *jobname_cstr = NULL;
static char *job_id_string = NULL;
-extern string ptexbanner; /* from web2c/lib/texmfmp.c */
-extern string versionstring; /* from web2c/lib/version.c */
-extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */
+extern string ptexbanner; /* from web2c/lib/texmfmp.c */
+extern string versionstring; /* from web2c/lib/version.c */
+extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */
-size_t last_ptr_index; /* for use with alloc_array */
+size_t last_ptr_index; /* for use with alloc_array */
/* define fb_ptr, fb_array & fb_limit */
typedef char fb_entry;
-define_array(fb);
+define_array(fb);
/* define char_ptr, char_array & char_limit */
typedef char char_entry;
-define_array(char);
+define_array(char);
+
+/* define vf_e_fnts_ptr, vf_e_fnts_array & vf_e_fnts_limit */
+typedef integer vf_e_fnts_entry;
+define_array(vf_e_fnts);
+
+/* define vf_i_fnts_ptr, vf_i_fnts_array & vf_i_fnts_limit */
+typedef internalfontnumber vf_i_fnts_entry;
+define_array(vf_i_fnts);
integer fb_offset(void)
{
@@ -60,7 +77,7 @@ integer fb_offset(void)
void fb_seek(integer offset)
{
- fb_ptr = fb_array + offset;
+ fb_ptr = fb_array + offset;
}
void fb_putchar(eightbits b)
@@ -77,7 +94,7 @@ void fb_flush(void)
n = pdfbufsize - pdfptr;
if (fb_ptr - p < n)
n = fb_ptr - p;
- memcpy(pdfbuf + pdfptr, p, (unsigned)n);
+ memcpy(pdfbuf + pdfptr, p, (unsigned) n);
pdfptr += n;
if (pdfptr == pdfbufsize)
pdfflush();
@@ -86,61 +103,52 @@ void fb_flush(void)
fb_ptr = fb_array;
}
-static void fnstr_append(const char *s)
-{
- int l = strlen(s) + 1;
- alloc_array(char, l, SMALL_ARRAY_SIZE);
- strcat(char_ptr, s);
- char_ptr = strend(char_ptr);
-}
+#define SUBSET_TAG_LENGTH 6
-void make_subset_tag(fm_entry *fm_cur, char **glyph_names)
+void make_subset_tag(fd_entry * fd)
{
- char tag[7];
- unsigned long crc;
- int i, l = strlen(job_id_string) + 1;
- alloc_array(char, l, SMALL_ARRAY_SIZE);
- strcpy(char_array, job_id_string);
- char_ptr = strend(char_array);
- if (fm_cur->tfm_name != NULL) {
- fnstr_append(" TFM name: ");
- fnstr_append(fm_cur->tfm_name);
- }
- fnstr_append(" PS name: ");
- if (font_keys[FONTNAME_CODE].valid)
- fnstr_append(fontname_buf);
- else if (fm_cur->ps_name != NULL)
- fnstr_append(fm_cur->ps_name);
- fnstr_append(" Encoding: ");
- if (fm_cur->encoding != NULL && (fm_cur->encoding)->name != NULL)
- fnstr_append((fm_cur->encoding)->name);
- else
- fnstr_append("built-in");
- fnstr_append(" CharSet: ");
- assert(glyph_names != NULL);
- for (i = 0; i <= MAX_CHAR_CODE; i++)
- if (pdfcharmarked(tex_font, i) && glyph_names[i] != notdef) {
- fnstr_append(" /");
- fnstr_append(glyph_names[i]);
+ int i, j = 0, a[SUBSET_TAG_LENGTH];
+ md5_state_t pms;
+ char *glyph;
+ struct avl_traverser t;
+ md5_byte_t digest[16];
+ void **aa;
+ static struct avl_table *st_tree = NULL;
+ if (st_tree == NULL)
+ st_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+ assert(fd != NULL);
+ assert(fd->gl_tree != NULL);
+ assert(fd->fontname != NULL);
+ assert(fd->subset_tag == NULL);
+ fd->subset_tag = xtalloc(SUBSET_TAG_LENGTH + 1, char);
+ do {
+ md5_init(&pms);
+ avl_t_init(&t, fd->gl_tree);
+ for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL;
+ glyph = (char *) avl_t_next(&t)) {
+ md5_append(&pms, (md5_byte_t *) glyph, strlen(glyph));
+ md5_append(&pms, (md5_byte_t *) " ", 1);
}
- if (fm_cur->charset != NULL) {
- fnstr_append(" Extra CharSet: ");
- fnstr_append(fm_cur->charset);
- }
- crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (Bytef*)char_array, strlen(char_array));
- /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
- * there are 26 uppercase chars ==> each char represents a number in range
- * 0..25. The maximal number that can be represented by the tag is
- * 26^6 - 1, which is a number between 2^28 and 2^29. Thus the bits 29..31
- * of the CRC must be dropped out.
- */
- for (i = 0; i < 6; i++) {
- tag[i] = 'A' + crc % 26;
- crc /= 26;
+ md5_append(&pms, (md5_byte_t *) fd->fontname, strlen(fd->fontname));
+ md5_append(&pms, (md5_byte_t *) & j, sizeof(int)); /* to resolve collision */
+ md5_finish(&pms, digest);
+ for (a[0] = 0, i = 0; i < 13; i++)
+ a[0] += digest[i];
+ for (i = 1; i < SUBSET_TAG_LENGTH; i++)
+ a[i] = a[i - 1] - digest[i - 1] + digest[(i + 12) % 16];
+ for (i = 0; i < SUBSET_TAG_LENGTH; i++)
+ fd->subset_tag[i] = a[i] % 26 + 'A';
+ fd->subset_tag[SUBSET_TAG_LENGTH] = '\0';
+ j++;
+ assert(j < 100);
}
- tag[6] = 0;
- fm_cur->subset_tag = xstrdup(tag);
+ while ((char *) avl_find(st_tree, fd->subset_tag) != NULL);
+ aa = avl_probe(st_tree, fd->subset_tag);
+ assert(aa != NULL);
+ if (j > 2)
+ pdftex_warn
+ ("\nmake_subset_tag(): subset-tag collision, resolved in round %d.\n",
+ j);
}
void pdf_puts(const char *s)
@@ -150,18 +158,19 @@ void pdf_puts(const char *s)
pdfbuf[pdfptr++] = *s++;
}
-void pdf_printf(const char *fmt,...)
+__attribute__ ((format(printf, 1, 2)))
+void pdf_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vsprintf(print_buf, fmt, args);
- pdf_puts(print_buf);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
+ pdf_puts(print_buf);
va_end(args);
}
strnumber maketexstring(const char *s)
{
- int l;
+ size_t l;
if (s == NULL || *s == 0)
return getnullstr();
l = strlen(s);
@@ -172,11 +181,12 @@ strnumber maketexstring(const char *s)
return last_tex_string;
}
+__attribute__ ((format(printf, 1, 2)))
void tex_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- vsprintf(print_buf, fmt, args);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
print(maketexstring(print_buf));
flushstr(last_tex_string);
xfflush(stdout);
@@ -191,16 +201,28 @@ static void safe_print(const char *str)
print(*c);
}
+void removepdffile(void)
+{
+ if (!kpathsea_debug && outputfilename && !fixedpdfdraftmode) {
+ xfclose(pdffile, makecstring(outputfilename));
+ remove(makecstring(outputfilename));
+ }
+}
+
/* pdftex_fail may be called when a buffer overflow has happened/is
happening, therefore may not call mktexstring. However, with the
current implementation it appears that error messages are misleading,
- possibly because pool overflows are detected too late. */
-void pdftex_fail(const char *fmt,...)
+ possibly because pool overflows are detected too late.
+
+ The output format of this fuction must be the same as pdf_error in
+ pdftex.web! */
+__attribute__ ((noreturn, format(printf, 1, 2)))
+void pdftex_fail(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
println();
- safe_print("Error: ");
+ safe_print("!pdfTeX error: ");
safe_print(program_invocation_name);
if (cur_file_name) {
safe_print(" (file ");
@@ -208,76 +230,97 @@ void pdftex_fail(const char *fmt,...)
safe_print(")");
}
safe_print(": ");
- vsprintf(print_buf, fmt, args);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
safe_print(print_buf);
va_end(args);
println();
- safe_print(" ==> Fatal error occurred, the output PDF file is not finished!");
+ removepdffile();
+ safe_print(" ==> Fatal error occurred, no output PDF file produced!");
println();
- exit(-1);
+ if (kpathsea_debug) {
+ abort();
+ } else {
+ exit(EX_SOFTWARE);
+ }
}
-void pdftex_warn(const char *fmt,...)
+/* The output format of this fuction must be the same as pdf_warn in
+ pdftex.web! */
+__attribute__ ((format(printf, 1, 2)))
+void pdftex_warn(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
println();
- tex_printf("Warning: %s", program_invocation_name);
+ println();
+ tex_printf("pdfTeX warning: %s", program_invocation_name);
if (cur_file_name)
tex_printf(" (file %s)", cur_file_name);
tex_printf(": ");
- vsprintf(print_buf, fmt, args);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
print(maketexstring(print_buf));
flushstr(last_tex_string);
va_end(args);
println();
}
+void garbagewarning(void)
+{
+ pdftex_warn("dangling objects discarded, no output file produced.");
+ removepdffile();
+}
+
char *makecstring(integer s)
{
- static char cstrbuf[MAX_CSTRING_LEN];
- char *p = cstrbuf;
- int i, l = strstart[s + 1] - strstart[s];
+ static char *cstrbuf = NULL;
+ char *p;
+ static int allocsize;
+ int allocgrow, i, l = strstart[s + 1] - strstart[s];
check_buf(l + 1, MAX_CSTRING_LEN);
+ if (cstrbuf == NULL) {
+ allocsize = l + 1;
+ cstrbuf = xmallocarray(char, allocsize);
+ } else if (l + 1 > allocsize) {
+ allocgrow = allocsize * 0.2;
+ if (l + 1 - allocgrow > allocsize)
+ allocsize = l + 1;
+ else if (allocsize < MAX_CSTRING_LEN - allocgrow)
+ allocsize += allocgrow;
+ else
+ allocsize = MAX_CSTRING_LEN;
+ cstrbuf = xreallocarray(cstrbuf, char, allocsize);
+ }
+ p = cstrbuf;
for (i = 0; i < l; i++)
*p++ = strpool[i + strstart[s]];
*p = 0;
return cstrbuf;
}
-/*
-boolean str_eq_cstr(strnumber n, char *s)
-{
- int l;
- if (s == NULL || n == 0)
- return false;
- l = strstart[n];
- while (*s && l < strstart[n + 1] && *s == strpool[l])
- l++, s++;
- return !*s && l == strstart[n + 1];
-}
-*/
-
-void setjobid(int year, int month, int day, int time, int pdftexversion, int pdftexrevision)
+void setjobid(int year, int month, int day, int time)
{
char *name_string, *format_string, *s;
+ size_t slen;
+ int i;
if (job_id_string != NULL)
return;
name_string = xstrdup(makecstring(jobname));
format_string = xstrdup(makecstring(formatident));
- s = xtalloc(SMALL_BUF_SIZE +
- strlen(name_string) +
- strlen(format_string) +
- strlen(ptexbanner) +
- strlen(versionstring) +
- strlen(kpathsea_version_string), char);
+ slen = SMALL_BUF_SIZE +
+ strlen(name_string) +
+ strlen(format_string) +
+ strlen(ptexbanner) +
+ strlen(versionstring) + strlen(kpathsea_version_string);
+ s = xtalloc(slen, char);
/* The Web2c version string starts with a space. */
- sprintf(s, "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
- year, month, day, time/60, time%60,
- name_string, format_string, ptexbanner,
- versionstring, kpathsea_version_string);
+ i = snprintf(s, slen,
+ "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
+ year, month, day, time / 60, time % 60,
+ name_string, format_string, ptexbanner,
+ versionstring, kpathsea_version_string);
+ check_nprintf(i, slen);
job_id_string = xstrdup(s);
xfree(s);
xfree(name_string);
@@ -288,16 +331,20 @@ void makepdftexbanner(void)
{
static boolean pdftexbanner_init = false;
char *s;
+ size_t slen;
+ int i;
if (pdftexbanner_init)
return;
- s = xtalloc(SMALL_BUF_SIZE +
- strlen(ptexbanner) +
- strlen(versionstring) +
- strlen(kpathsea_version_string), char);
+ slen = SMALL_BUF_SIZE +
+ strlen(ptexbanner) +
+ strlen(versionstring) + strlen(kpathsea_version_string);
+ s = xtalloc(slen, char);
/* The Web2c version string starts with a space. */
- sprintf(s, "%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
+ i = snprintf(s, slen,
+ "%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
+ check_nprintf(i, slen);
pdftexbanner = maketexstring(s);
xfree(s);
pdftexbanner_init = true;
@@ -309,12 +356,13 @@ strnumber getresnameprefix(void)
/* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */
/* "^_`abcdefghijklmnopqrstuvwxyz|~"; */
static char name_str[] =
-"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- char prefix[7]; /* make a tag of 6 chars long */
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ char prefix[7]; /* make a tag of 6 chars long */
unsigned long crc;
- int i, base = strlen(name_str);
+ int i;
+ size_t base = strlen(name_str);
crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (Bytef*)job_id_string, strlen(job_id_string));
+ crc = crc32(crc, (Bytef *) job_id_string, strlen(job_id_string));
for (i = 0; i < 6; i++) {
prefix[i] = name_str[crc % base];
crc /= base;
@@ -323,21 +371,21 @@ strnumber getresnameprefix(void)
return maketexstring(prefix);
}
-size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
+size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE * stream)
{
if (fwrite(ptr, size, nmemb, stream) != nmemb)
pdftex_fail("fwrite() failed");
return nmemb;
}
-int xfflush(FILE *stream)
+int xfflush(FILE * stream)
{
if (fflush(stream) != 0)
pdftex_fail("fflush() failed");
return 0;
}
-int xgetc(FILE *stream)
+int xgetc(FILE * stream)
{
int c = getc(stream);
if (c < 0 && c != EOF)
@@ -345,7 +393,7 @@ int xgetc(FILE *stream)
return c;
}
-int xputc(int c, FILE *stream)
+int xputc(int c, FILE * stream)
{
int i = putc(c, stream);
if (i < 0)
@@ -355,25 +403,25 @@ int xputc(int c, FILE *stream)
void writestreamlength(integer length, integer offset)
{
- integer save_offset;
if (jobname_cstr == NULL)
jobname_cstr = xstrdup(makecstring(jobname));
- save_offset = xftell(pdffile, jobname_cstr);
- xfseek(pdffile, offset, SEEK_SET, jobname_cstr);
- fprintf(pdffile, "%li", (long int)length);
- xfseek(pdffile, pdfoffset(), SEEK_SET, jobname_cstr);
+ if (fixedpdfdraftmode == 0) {
+ xfseek(pdffile, offset, SEEK_SET, jobname_cstr);
+ fprintf(pdffile, "%li", (long int) length);
+ xfseek(pdffile, pdfoffset(), SEEK_SET, jobname_cstr);
+ }
}
scaled extxnoverd(scaled x, scaled n, scaled d)
{
- double r = (((double)x)*((double)n))/((double)d);
- if (r > 0)
+ double r = (((double) x) * ((double) n)) / ((double) d);
+ if (r > DBL_EPSILON)
r += 0.5;
else
r -= 0.5;
- if (r >= (double)maxinteger || r <= -(double)maxinteger)
+ if (r >= (double) maxinteger || r <= -(double) maxinteger)
pdftex_warn("arithmetic: number too big");
- return r;
+ return (scaled) r;
}
void libpdffinish()
@@ -387,6 +435,9 @@ void libpdffinish()
img_free();
vf_free();
epdf_free();
+ ttf_free();
+ sfd_free();
+ glyph_unicode_free();
}
/* Converts any string given in in in an allowed PDF string which can be
@@ -395,38 +446,36 @@ void libpdffinish()
* This assumes that the string does not contain any already escaped
* characters!
*/
-char *convertStringToPDFString (char *in, int len)
+char *convertStringToPDFString(const char *in, int len)
{
static char pstrbuf[MAX_PSTRING_LEN];
char *out = pstrbuf;
- int i, j;
+ int i, j = 0, k;
char buf[5];
- j = 0;
for (i = 0; i < len; i++) {
check_buf(j + sizeof(buf), MAX_PSTRING_LEN);
- if (((unsigned char)in[i] < '!') || ((unsigned char)in[i] > '~')){
+ if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) {
/* convert control characters into oct */
- sprintf (buf, "\\%03o", (unsigned int)(unsigned char)in[i]);
+ k = snprintf(buf, sizeof(buf),
+ "\\%03o", (unsigned int) (unsigned char) in[i]);
+ check_nprintf(k, sizeof(buf));
out[j++] = buf[0];
out[j++] = buf[1];
out[j++] = buf[2];
out[j++] = buf[3];
- }
- else if ((in[i] == '(') || (in[i] == ')')) {
+ } else if ((in[i] == '(') || (in[i] == ')')) {
/* escape paranthesis */
out[j++] = '\\';
out[j++] = in[i];
- }
- else if (in[i] == '\\') {
+ } else if (in[i] == '\\') {
/* escape backslash */
out[j++] = '\\';
out[j++] = '\\';
- }
- else {
+ } else {
/* copy char :-) */
out[j++] = in[i];
- }
}
+ }
out[j] = '\0';
return pstrbuf;
}
@@ -442,7 +491,7 @@ char *convertStringToPDFString (char *in, int len)
*/
void escapestring(poolpointer in)
{
- poolpointer out = poolptr;
+ const poolpointer out = poolptr;
unsigned char ch;
while (in < out) {
if (poolptr + 4 >= poolsize) {
@@ -450,13 +499,15 @@ void escapestring(poolpointer in)
/* error by str_toks that calls str_room(1) */
return;
}
-
- ch = (unsigned char)strpool[in++];
-
+
+ ch = (unsigned char) strpool[in++];
+
if ((ch < '!') || (ch > '~')) {
/* convert control characters into oct */
- sprintf (&strpool[poolptr], "\\%.3o", (unsigned int)ch);
- poolptr += 4;
+ int i = snprintf((char *) &strpool[poolptr], 5,
+ "\\%.3o", (unsigned int) ch);
+ check_nprintf(i, 5);
+ poolptr += i;
continue;
}
if ((ch == '(') || (ch == ')') || (ch == '\\')) {
@@ -468,10 +519,9 @@ void escapestring(poolpointer in)
}
}
-
/* Convert any given string in a PDF name using escaping mechanism
of PDF 1.2. The result does not include the leading slash.
-
+
PDF specification 1.6, section 3.2.6 "Name Objects" explains:
<blockquote>
Beginning with PDF 1.2, any character except null (character code 0) may
@@ -502,7 +552,7 @@ void escapestring(poolpointer in)
125 escaped delimiter "}"
127..255 escaped recommended
else copy regular characters
-
+
Parameter "in" is a pointer into the string pool where
the input string is located. The output string is written
as temporary string right after the input string.
@@ -512,22 +562,25 @@ void escapestring(poolpointer in)
*/
void escapename(poolpointer in)
{
- poolpointer out = poolptr;
+ const poolpointer out = poolptr;
unsigned char ch;
-
+ int i;
+
while (in < out) {
if (poolptr + 3 >= poolsize) {
poolptr = poolsize;
/* error by str_toks that calls str_room(1) */
return;
}
-
- ch = (unsigned char)strpool[in++];
-
+
+ ch = (unsigned char) strpool[in++];
+
if ((ch >= 1 && ch <= 32) || ch >= 127) {
/* escape */
- sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch);
- poolptr += 3;
+ i = snprintf((char *) &strpool[poolptr], 4,
+ "#%.2X", (unsigned int) ch);
+ check_nprintf(i, 4);
+ poolptr += i;
continue;
}
switch (ch) {
@@ -546,8 +599,10 @@ void escapename(poolpointer in)
case 123:
case 125:
/* escape */
- sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch);
- poolptr += 3;
+ i = snprintf((char *) &strpool[poolptr], 4,
+ "#%.2X", (unsigned int) ch);
+ check_nprintf(i, 4);
+ poolptr += i;
break;
default:
/* copy */
@@ -558,16 +613,17 @@ void escapename(poolpointer in)
/* Convert any given string in a PDF hexadecimal string. The
result does not include the angle brackets.
-
+
This procedure uses uppercase hexadecimal letters.
-
+
See escapename for description of parameters.
*/
void escapehex(poolpointer in)
{
- poolpointer out = poolptr;
+ const poolpointer out = poolptr;
unsigned char ch;
-
+ int i;
+
while (in < out) {
if (poolptr + 2 >= poolsize) {
poolptr = poolsize;
@@ -575,9 +631,10 @@ void escapehex(poolpointer in)
return;
}
- ch = (unsigned char)strpool[in++];
-
- sprintf(&strpool[poolptr], "%.2X", (unsigned int)ch);
+ ch = (unsigned char) strpool[in++];
+
+ i = snprintf((char *) &strpool[poolptr], 3, "%.2X", (unsigned int) ch);
+ check_nprintf(i, 3);
poolptr += 2;
}
}
@@ -586,17 +643,18 @@ void escapehex(poolpointer in)
Last hex digit can be omitted, it is replaced by zero, see
PDF specification.
-
+
Invalid digits are silently ignored.
See escapename for description of parameters.
*/
void unescapehex(poolpointer in)
{
- poolpointer out = poolptr;
- unsigned char ch, a;
+ const poolpointer out = poolptr;
+ unsigned char ch;
+ unsigned char a = 0; /* to avoid warning about uninitialized use of a */
boolean first = true;
-
+
while (in < out) {
if (poolptr + 1 >= poolsize) {
poolptr = poolsize;
@@ -604,50 +662,49 @@ void unescapehex(poolpointer in)
return;
}
- ch = (unsigned char)strpool[in++];
+ ch = (unsigned char) strpool[in++];
if ((ch >= '0') && (ch <= '9')) {
ch -= '0';
- }
- else if ((ch >= 'A') && (ch <= 'F')) {
+ } else if ((ch >= 'A') && (ch <= 'F')) {
ch -= 'A' - 10;
- }
- else if ((ch >= 'a') && (ch <= 'f')) {
+ } else if ((ch >= 'a') && (ch <= 'f')) {
ch -= 'a' - 10;
+ } else {
+ continue; /* ignore wrong character */
}
- else {
- continue; /* ignore wrong character */
- }
-
+
if (first) {
a = ch << 4;
first = false;
continue;
}
-
+
strpool[poolptr++] = a + ch;
first = true;
}
- if (!first) { /* last hex digit is omitted */
+ if (!first) { /* last hex digit is omitted */
strpool[poolptr++] = ch << 4;
}
}
-/* Converts any string given in in in an allowed PDF string which is
+/* Converts any string given in in in an allowed PDF string which is
* hexadecimal encoded;
* sizeof(out) should be at least lin*2+1.
*/
-void convertStringToHexString (char *in, char *out, int lin)
+static void convertStringToHexString(const char *in, char *out, int lin)
{
- int i, j;
+ int i, j, k;
char buf[3];
j = 0;
for (i = 0; i < lin; i++) {
- sprintf (buf, "%02X", (unsigned int)(unsigned char)in[i]);
+ k = snprintf(buf, sizeof(buf),
+ "%02X", (unsigned int) (unsigned char) in[i]);
+ check_nprintf(k, sizeof(buf));
out[j++] = buf[0];
out[j++] = buf[1];
- }
+ }
out[j] = '\0';
}
@@ -664,15 +721,15 @@ void convertStringToHexString (char *in, char *out, int lin)
identifiers are set to the same value. If both identifiers match when a
file reference is resolved, it is very likely that the correct file has
been found; if only the first identifier matches, then a different
- version of the correct file has been found.
+ version of the correct file has been found.
To help ensure the uniqueness of file identifiers, it is recommend
that they be computed using a message digest algorithm such as MD5
(described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see
the Bibliography), using the following information (see implementation
- note 106 in Appendix H):
- - The current time
- - A string representation of the file's location, usually a pathname
- - The size of the file in bytes
+ note 106 in Appendix H):
+ - The current time
+ - A string representation of the file's location, usually a pathname
+ - The size of the file in bytes
- The values of all entries in the file's document information
dictionary (see Section 9.2.1, Document Information Dictionary )
</blockquote>
@@ -682,7 +739,7 @@ void convertStringToHexString (char *in, char *out, int lin)
scanning the info dict is also difficult, we start with a simpler
implementation using just the first two items.
*/
-void printID (strnumber filename)
+void printID(strnumber filename)
{
time_t t;
size_t size;
@@ -696,19 +753,19 @@ void printID (strnumber filename)
md5_init(&state);
/* get the time */
t = time(NULL);
- size = strftime (time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
- md5_append(&state, (const md5_byte_t *)time_str, size);
+ size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
+ md5_append(&state, (const md5_byte_t *) time_str, size);
/* get the file name */
if (getcwd(pwd, sizeof(pwd)) == NULL)
pdftex_fail("getcwd() failed (path too long?)");
file_name = makecstring(filename);
- md5_append(&state, (const md5_byte_t *)pwd, strlen(pwd));
- md5_append(&state, (const md5_byte_t *)"/", 1);
- md5_append(&state, (const md5_byte_t *)file_name, strlen(file_name));
+ md5_append(&state, (const md5_byte_t *) pwd, strlen(pwd));
+ md5_append(&state, (const md5_byte_t *) "/", 1);
+ md5_append(&state, (const md5_byte_t *) file_name, strlen(file_name));
/* finish md5 */
md5_finish(&state, digest);
/* write the IDs */
- convertStringToHexString ((char*)digest, id, 16);
+ convertStringToHexString((char *) digest, id, 16);
pdf_printf("/ID [<%s> <%s>]", id, id);
}
@@ -759,22 +816,22 @@ void printID (strnumber filename)
The main difficulty is get the time zone offset. strftime() does this in ISO
C99 (e.g. newer glibc) with %z, but we have to work with other systems (e.g.
- Solaris 2.5).
+ Solaris 2.5).
*/
-time_t start_time = 0;
+static time_t start_time = 0;
#define TIME_STR_SIZE 30
-char start_time_str[TIME_STR_SIZE];
-char time_str[TIME_STR_SIZE];
+static char start_time_str[TIME_STR_SIZE];
+static char time_str[TIME_STR_SIZE];
/* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */
-
-void makepdftime(time_t t, char *time_str)
+
+static void makepdftime(time_t t, char *time_str)
{
-
+
struct tm lt, gmt;
size_t size;
- int off, off_hours, off_mins;
-
+ int i, off, off_hours, off_mins;
+
/* get the time */
lt = *localtime(&t);
size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", &lt);
@@ -786,59 +843,64 @@ void makepdftime(time_t t, char *time_str)
}
/* correction for seconds: %S can be in range 00..61,
- the PDF reference expects 00..59,
+ the PDF reference expects 00..59,
therefore we map "60" and "61" to "59" */
if (time_str[14] == '6') {
time_str[14] = '5';
time_str[15] = '9';
- time_str[16] = '\0'; /* for safety */
+ time_str[16] = '\0'; /* for safety */
}
/* get the time zone offset */
gmt = *gmtime(&t);
/* this calculation method was found in exim's tod.c */
- off = 60*(lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
+ off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
if (lt.tm_year != gmt.tm_year) {
off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440;
- }
- else if (lt.tm_yday != gmt.tm_yday) {
+ } else if (lt.tm_yday != gmt.tm_yday) {
off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440;
}
if (off == 0) {
time_str[size++] = 'Z';
time_str[size] = 0;
- }
- else {
- off_hours = off/60;
- off_mins = abs(off - off_hours*60);
- sprintf(&time_str[size], "%+03i'%02d'", off_hours, off_mins);
+ } else {
+ off_hours = off / 60;
+ off_mins = abs(off - off_hours * 60);
+ i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins);
+ check_nprintf(i, 9);
}
}
-void initstarttime() {
+void initstarttime()
+{
if (start_time == 0) {
start_time = time((time_t *) NULL);
makepdftime(start_time, start_time_str);
}
}
-void printcreationdate() {
+void printcreationdate()
+{
initstarttime();
pdf_printf("/CreationDate (%s)\n", start_time_str);
}
+void printmoddate()
+{
+ initstarttime();
+ pdf_printf("/ModDate (%s)\n", start_time_str);
+}
+
void getcreationdate()
{
/* put creation date on top of string pool and update poolptr */
- poolpointer out = poolptr;
- unsigned char ch;
- int len = strlen(start_time_str);
-
+ size_t len = strlen(start_time_str);
+
initstarttime();
-
- if (poolptr + len >= poolsize) {
+
+ if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
poolptr = poolsize;
/* error by str_toks that calls str_room(1) */
return;
@@ -848,121 +910,124 @@ void getcreationdate()
poolptr += len;
}
-void getfilemoddate(strnumber s) {
+void getfilemoddate(strnumber s)
+{
struct stat file_data;
-
+
char *file_name = kpse_find_tex(makecfilename(s));
if (file_name == NULL) {
- return; /* empty string */
+ return; /* empty string */
}
-
+
/* get file status */
if (stat(file_name, &file_data) == 0) {
- int len;
-
+ size_t len;
+
makepdftime(file_data.st_mtime, time_str);
len = strlen(time_str);
- if (poolptr + len >= poolsize) {
+ if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
poolptr = poolsize;
/* error by str_toks that calls str_room(1) */
- }
- else {
+ } else {
memcpy(&strpool[poolptr], time_str, len);
poolptr += len;
}
}
/* else { errno contains error code } */
-
+
xfree(file_name);
}
-void getfilesize(strnumber s) {
+void getfilesize(strnumber s)
+{
struct stat file_data;
-
+ int i;
+
char *file_name = kpse_find_tex(makecfilename(s));
if (file_name == NULL) {
- return; /* empty string */
+ return; /* empty string */
}
-
+
/* get file status */
if (stat(file_name, &file_data) == 0) {
- int len;
+ size_t len;
char buf[20];
-
+
/* st_size has type off_t */
- sprintf(buf, "%lu", (long unsigned int)file_data.st_size);
+ i = snprintf(buf, sizeof(buf),
+ "%lu", (long unsigned int) file_data.st_size);
+ check_nprintf(i, sizeof(buf));
len = strlen(buf);
- if (poolptr + len >= poolsize) {
+ if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
poolptr = poolsize;
/* error by str_toks that calls str_room(1) */
- }
- else {
+ } else {
memcpy(&strpool[poolptr], buf, len);
poolptr += len;
}
}
/* else { errno contains error code } */
-
+
xfree(file_name);
}
#define DIGEST_SIZE 16
#define FILE_BUF_SIZE 1024
-void getmd5sum(strnumber s, boolean file) {
+void getmd5sum(strnumber s, boolean file)
+{
md5_state_t state;
md5_byte_t digest[DIGEST_SIZE];
char outbuf[2 * DIGEST_SIZE + 1];
int len = 2 * DIGEST_SIZE;
-
+
if (file) {
char file_buf[FILE_BUF_SIZE];
int read = 0;
FILE *f;
-
+
char *file_name = kpse_find_tex(makecfilename(s));
if (file_name == NULL) {
- return; /* empty string */
+ return; /* empty string */
}
/* in case of error the empty string is returned,
no need for xfopen that aborts on error.
- */
+ */
f = fopen(file_name, FOPEN_RBIN_MODE);
if (f == NULL) {
xfree(file_name);
return;
}
md5_init(&state);
- while ((read = fread(&file_buf, sizeof(char),
- FILE_BUF_SIZE, f)) > 0) {
- md5_append(&state, (const md5_byte_t *)file_buf, read);
+ while ((read = fread(&file_buf, sizeof(char), FILE_BUF_SIZE, f)) > 0) {
+ md5_append(&state, (const md5_byte_t *) file_buf, read);
}
md5_finish(&state, digest);
fclose(f);
-
+
xfree(file_name);
+ } else {
+ /* s contains the data */
+ md5_init(&state);
+ md5_append(&state,
+ (const md5_byte_t *) &strpool[strstart[s]],
+ strstart[s + 1] - strstart[s]);
+ md5_finish(&state, digest);
}
- else {
- /* s contains the data */
- md5_init(&state);
- md5_append(&state,
- (const md5_byte_t *)&strpool[strstart[s]],
- strstart[s + 1] - strstart[s]);
- md5_finish(&state, digest);
- }
-
+
if (poolptr + len >= poolsize) {
/* error by str_toks that calls str_room(1) */
return;
}
- convertStringToHexString((char*)digest, outbuf, DIGEST_SIZE);
+ convertStringToHexString((char *) digest, outbuf, DIGEST_SIZE);
memcpy(&strpool[poolptr], outbuf, len);
poolptr += len;
}
-void getfiledump(strnumber s, int offset, int length) {
+void getfiledump(strnumber s, int offset, int length)
+{
FILE *f;
- int read;
+ int read, i;
poolpointer data_ptr;
poolpointer data_end;
char *file_name;
@@ -971,136 +1036,128 @@ void getfiledump(strnumber s, int offset, int length) {
/* empty result string */
return;
}
-
+
if (poolptr + 2 * length + 1 >= poolsize) {
/* no place for result */
poolptr = poolsize;
/* error by str_toks that calls str_room(1) */
return;
}
-
+
file_name = kpse_find_tex(makecfilename(s));
if (file_name == NULL) {
- return; /* empty string */
+ return; /* empty string */
}
-
+
/* read file data */
f = fopen(file_name, FOPEN_RBIN_MODE);
if (f == NULL) {
xfree(file_name);
return;
}
- if (fseek(f, (long)offset, SEEK_SET) != 0) {
+ if (fseek(f, (long) offset, SEEK_SET) != 0) {
xfree(file_name);
return;
}
/* there is enough space in the string pool, the read
data are put in the upper half of the result, thus
the conversion to hex can be done without overwriting
- unconverted bytes. Be aware that sprintf also appends
- a nul byte at the end. */
+ unconverted bytes. */
data_ptr = poolptr + length;
- read = fread(&strpool[data_ptr],
- sizeof(char), length, f);
+ read = fread(&strpool[data_ptr], sizeof(char), length, f);
fclose(f);
/* convert to hex */
data_end = data_ptr + read;
for (; data_ptr < data_end; data_ptr++) {
- sprintf(&strpool[poolptr], "%.2X",
- (unsigned int)strpool[data_ptr]);
- poolptr += 2;
+ i = snprintf((char *) &strpool[poolptr], 3,
+ "%.2X", (unsigned int) strpool[data_ptr]);
+ check_nprintf(i, 3);
+ poolptr += i;
}
xfree(file_name);
}
#define DEFAULT_SUB_MATCH_COUNT 10
-int sub_match_count = DEFAULT_SUB_MATCH_COUNT;
-regmatch_t *pmatch = NULL;
-char *match_string = NULL;
+static int sub_match_count = DEFAULT_SUB_MATCH_COUNT;
+static regmatch_t *pmatch = NULL;
+static char *match_string = NULL;
-void matchstrings(strnumber s, strnumber t, int subcount, boolean icase) {
+void matchstrings(strnumber s, strnumber t, int subcount, boolean icase)
+{
regex_t preg;
int cflags = REG_EXTENDED;
int eflags = 0;
int ret;
char *str;
-
+
if (icase) {
cflags |= REG_ICASE;
}
-
+
if (poolptr + 10 >= poolsize) {
poolptr = poolsize;
return;
}
-
+
str = makecstring(s);
ret = regcomp(&preg, str, cflags);
if (ret != 0) {
- int size = regerror(ret, &preg, NULL, 0);
+ size_t size = regerror(ret, &preg, NULL, 0);
str = xtalloc(size, char);
regerror(ret, &preg, str, size);
pdftex_warn("%s%s", "\\pdfmatch: ", str);
xfree(str);
strpool[poolptr++] = '-';
strpool[poolptr++] = '1';
- }
- else {
+ } else {
str = makecstring(t);
- sub_match_count = ((subcount < 0) ?
- DEFAULT_SUB_MATCH_COUNT : subcount);
+ sub_match_count = ((subcount < 0) ? DEFAULT_SUB_MATCH_COUNT : subcount);
xfree(pmatch);
if (sub_match_count > 0) {
- pmatch = xtalloc(sub_match_count, regmatch_t);
+ pmatch = xtalloc(sub_match_count, regmatch_t);
}
ret = regexec(&preg, str, sub_match_count, pmatch, eflags);
xfree(match_string);
match_string = xstrdup(str);
- if (ret == 0) {
- strpool[poolptr++] = '1';
- }
- else { /* REG_NOMATCH */
- strpool[poolptr++] = '0';
- }
+ strpool[poolptr++] = ((ret == 0) ? '1' : '0');
}
-
+
regfree(&preg);
}
-void getmatch(int i) {
- int size = 0;
- int len = 0;
-
+void getmatch(int i)
+{
+ int size, len = 0; /* to avoid warning about uninitialized use of len */
+
boolean found = i < sub_match_count
- && match_string != NULL
- && pmatch[i].rm_so >= 0
- && i >= 0;
-
+ && match_string != NULL && pmatch[i].rm_so >= 0 && i >= 0;
+
if (found) {
len = pmatch[i].rm_eo - pmatch[i].rm_so;
size = 20 + len;
/* 20: place for integer number and '->' */
- }
- else {
+ } else {
size = 4;
}
-
+
if (poolptr + size >= poolsize) {
poolptr = poolsize;
return;
}
-
+
if (found) {
- sprintf(&strpool[poolptr], "%d", pmatch[i].rm_so);
- poolptr += strlen(&strpool[poolptr]);
+ int j = snprintf((char *) &strpool[poolptr], 20, "%d",
+ (int) pmatch[i].rm_so);
+ check_nprintf(j, 20);
+ poolptr += j;
strpool[poolptr++] = '-';
strpool[poolptr++] = '>';
memcpy(&strpool[poolptr], &match_string[pmatch[i].rm_so], len);
poolptr += len;
return;
}
-
+
strpool[poolptr++] = '-';
strpool[poolptr++] = '1';
strpool[poolptr++] = '-';
@@ -1112,8 +1169,11 @@ void getmatch(int i) {
input/ouput same as makecstring:
input: string number
output: C string with quotes removed.
+ That means, file names that are legal on some operation systems
+ cannot any more be used since pdfTeX version 1.30.4.
*/
-char *makecfilename(strnumber s) {
+char *makecfilename(strnumber s)
+{
char *name = makecstring(s);
char *p = name;
char *q = name;
@@ -1124,6 +1184,641 @@ char *makecfilename(strnumber s) {
p++;
}
*q = '\0';
- fprintf(stderr, " %s\n", name);
return name;
}
+
+/* function strips trailing zeros in string with numbers; */
+/* leading zeros are not stripped (as in real life) */
+char *stripzeros(char *a)
+{
+ enum { NONUM, DOTNONUM, INT, DOT, LEADDOT, FRAC } s = NONUM, t = NONUM;
+ char *p, *q, *r;
+ for (p = q = r = a; *p != '\0';) {
+ switch (s) {
+ case NONUM:
+ if (*p >= '0' && *p <= '9')
+ s = INT;
+ else if (*p == '.')
+ s = LEADDOT;
+ break;
+ case DOTNONUM:
+ if (*p != '.' && (*p < '0' || *p > '9'))
+ s = NONUM;
+ break;
+ case INT:
+ if (*p == '.')
+ s = DOT;
+ else if (*p < '0' || *p > '9')
+ s = NONUM;
+ break;
+ case DOT:
+ case LEADDOT:
+ if (*p >= '0' && *p <= '9')
+ s = FRAC;
+ else if (*p == '.')
+ s = DOTNONUM;
+ else
+ s = NONUM;
+ break;
+ case FRAC:
+ if (*p == '.')
+ s = DOTNONUM;
+ else if (*p < '0' || *p > '9')
+ s = NONUM;
+ break;
+ default:;
+ }
+ switch (s) {
+ case DOT:
+ r = q;
+ break;
+ case LEADDOT:
+ r = q + 1;
+ break;
+ case FRAC:
+ if (*p > '0')
+ r = q + 1;
+ break;
+ case NONUM:
+ if ((t == FRAC || t == DOT) && r != a) {
+ q = r--;
+ if (*r == '.') /* was a LEADDOT */
+ *r = '0';
+ r = a;
+ }
+ break;
+ default:;
+ }
+ *q++ = *p++;
+ t = s;
+ }
+ *q = '\0';
+ return a;
+}
+
+void initversionstring(char **versions)
+{
+ (void) asprintf(versions,
+ "Compiled with libpng %s; using libpng %s\n"
+ "Compiled with zlib %s; using zlib %s\n"
+ "Compiled with xpdf version %s\n",
+ PNG_LIBPNG_VER_STRING, png_libpng_ver,
+ ZLIB_VERSION, zlib_version, xpdfVersion);
+}
+
+
+/*************************************************/
+/* Color Stack and Matrix Transformation Support */
+/*************************************************/
+
+/*
+ In the following array and especially stack data structures are used.
+ They have the following properties:
+ - They automatically grow dynamically.
+ - The size never decreases.
+ - The variable with name ending in "size" contains the number how many
+ entries the data structure can hold.
+ - The variable with name ending in "used" contains the number of
+ actually used entries.
+ - Memory of strings in stack entries must be allocated and
+ freed if the stack is cleared.
+*/
+
+/* Color Stack */
+
+#define STACK_INCREMENT 8
+#define MAX_COLORSTACKS 32768
+/* The colorstack number is stored in two bytes (info field of the node) */
+/* Condition (newcolorstack): MAX_COLORSTACKS mod STACK_INCREMENT = 0 */
+
+#define COLOR_DEFAULT "0 g 0 G"
+/* literal_modes, see pdftex.web */
+#define SET_ORIGIN 0
+#define DIRECT_PAGE 1
+#define DIRECT_ALWAYS 2
+
+/* remember shipout mode: page/form */
+static boolean page_mode;
+
+typedef struct {
+ char **page_stack;
+ char **form_stack;
+ char *page_current;
+ char *form_current;
+ char *form_init;
+ int page_size;
+ int form_size;
+ int page_used;
+ int form_used;
+ int literal_mode;
+ boolean page_start;
+} colstack_type;
+
+static colstack_type *colstacks = NULL;
+static int colstacks_size = 0;
+static int colstacks_used = 0;
+
+/*
+ Initialization is done, if the color stacks are used,
+ init_colorstacks() is defined as macro to avoid unnecessary
+ procedure calls.
+*/
+#define init_colorstacks() if (colstacks_size == 0) colstacks_first_init();
+void colstacks_first_init()
+{
+ colstacks_size = STACK_INCREMENT;
+ colstacks = xtalloc(colstacks_size, colstack_type);
+ colstacks_used = 1;
+ colstacks[0].page_stack = NULL;
+ colstacks[0].form_stack = NULL;
+ colstacks[0].page_size = 0;
+ colstacks[0].form_size = 0;
+ colstacks[0].page_used = 0;
+ colstacks[0].form_used = 0;
+ colstacks[0].page_current = xstrdup(COLOR_DEFAULT);
+ colstacks[0].form_current = xstrdup(COLOR_DEFAULT);
+ colstacks[0].form_init = xstrdup(COLOR_DEFAULT);
+ colstacks[0].literal_mode = DIRECT_ALWAYS;
+ colstacks[0].page_start = true;
+}
+
+int colorstackused()
+{
+ init_colorstacks();
+ return colstacks_used;
+}
+
+/*
+ newcolorstack()
+ A new color stack is setup with the given parameters.
+ The stack number is returned or -1 in case of error (no room).
+*/
+int newcolorstack(integer s, integer literal_mode, boolean page_start)
+{
+ colstack_type *colstack;
+ int colstack_num;
+ char *str;
+
+ init_colorstacks();
+
+ /* make room */
+ if (colstacks_used == MAX_COLORSTACKS) {
+ return -1;
+ }
+ if (colstacks_used == colstacks_size) {
+ colstacks_size += STACK_INCREMENT;
+ /* If (MAX_COLORSTACKS mod STACK_INCREMENT = 0) then we don't
+ need to check the case that size overruns MAX_COLORSTACKS. */
+ colstacks = xretalloc(colstacks, colstacks_size, colstack_type);
+ }
+ /* claim new color stack */
+ colstack_num = colstacks_used++;
+ colstack = &colstacks[colstack_num];
+ /* configure the new color stack */
+ colstack->literal_mode = literal_mode;
+ colstack->page_start = page_start;
+ str = makecstring(s);
+ if (*str == 0) {
+ colstack->page_current = NULL;
+ colstack->form_current = NULL;
+ colstack->form_init = NULL;
+ } else {
+ colstack->page_current = xstrdup(str);
+ colstack->form_current = xstrdup(str);
+ colstack->form_init = xstrdup(str);
+ }
+ return colstack_num;
+}
+
+#define get_colstack(n) (&colstacks[n])
+
+/*
+ Puts a string on top of the string pool and updates poolptr.
+*/
+void put_cstring_on_strpool(poolpointer start, char *str)
+{
+ size_t len;
+
+ if (str == NULL || *str == 0) {
+ return;
+ }
+
+ len = strlen(str);
+ poolptr = start + len;
+ if (poolptr >= poolsize) {
+ poolptr = poolsize;
+ /* error by str_toks that calls str_room(1) */
+ return;
+ }
+ memcpy(&strpool[start], str, len);
+}
+
+integer colorstackset(int colstack_no, integer s)
+{
+ colstack_type *colstack = get_colstack(colstack_no);
+
+ if (page_mode) {
+ xfree(colstack->page_current);
+ colstack->page_current = xstrdup(makecstring(s));
+ } else {
+ xfree(colstack->form_current);
+ colstack->form_current = xstrdup(makecstring(s));
+ }
+ return colstack->literal_mode;
+}
+
+integer colorstackcurrent(int colstack_no)
+{
+ colstack_type *colstack = get_colstack(colstack_no);
+
+ if (page_mode) {
+ put_cstring_on_strpool(poolptr, colstack->page_current);
+ } else {
+ put_cstring_on_strpool(poolptr, colstack->form_current);
+ }
+ return colstack->literal_mode;
+}
+
+integer colorstackpush(int colstack_no, integer s)
+{
+ colstack_type *colstack = get_colstack(colstack_no);
+ char *str;
+
+ if (page_mode) {
+ if (colstack->page_used == colstack->page_size) {
+ colstack->page_size += STACK_INCREMENT;
+ colstack->page_stack = xretalloc(colstack->page_stack,
+ colstack->page_size, char *);
+ }
+ colstack->page_stack[colstack->page_used++] = colstack->page_current;
+ str = makecstring(s);
+ if (*str == 0) {
+ colstack->page_current = NULL;
+ } else {
+ colstack->page_current = xstrdup(str);
+ }
+ } else {
+ if (colstack->form_used == colstack->form_size) {
+ colstack->form_size += STACK_INCREMENT;
+ colstack->form_stack = xretalloc(colstack->form_stack,
+ colstack->form_size, char *);
+ }
+ colstack->form_stack[colstack->form_used++] = colstack->form_current;
+ str = makecstring(s);
+ if (*str == 0) {
+ colstack->form_current = NULL;
+ } else {
+ colstack->form_current = xstrdup(str);
+ }
+ }
+ return colstack->literal_mode;
+}
+
+integer colorstackpop(int colstack_no)
+{
+ colstack_type *colstack = get_colstack(colstack_no);
+
+ if (page_mode) {
+ if (colstack->page_used == 0) {
+ pdftex_warn("pop empty color page stack %u",
+ (unsigned int) colstack_no);
+ return colstack->literal_mode;
+ }
+ xfree(colstack->page_current);
+ colstack->page_current = colstack->page_stack[--colstack->page_used];
+ put_cstring_on_strpool(poolptr, colstack->page_current);
+ } else {
+ if (colstack->form_used == 0) {
+ pdftex_warn("pop empty color form stack %u",
+ (unsigned int) colstack_no);
+ return colstack->literal_mode;
+ }
+ xfree(colstack->form_current);
+ colstack->form_current = colstack->form_stack[--colstack->form_used];
+ put_cstring_on_strpool(poolptr, colstack->form_current);
+ }
+ return colstack->literal_mode;
+}
+
+void colorstackpagestart()
+{
+ int i, j;
+ colstack_type *colstack;
+
+ if (page_mode) {
+ /* see procedure pdf_out_colorstack_startpage */
+ return;
+ }
+
+ for (i = 0; i < colstacks_used; i++) {
+ colstack = &colstacks[i];
+ for (j = 0; j < colstack->form_used; j++) {
+ xfree(colstack->form_stack[j]);
+ }
+ colstack->form_used = 0;
+ xfree(colstack->form_current);
+ if (colstack->form_init == NULL) {
+ colstack->form_current = NULL;
+ } else {
+ colstack->form_current = xstrdup(colstack->form_init);
+ }
+ }
+}
+
+integer colorstackskippagestart(int colstack_no)
+{
+ colstack_type *colstack = get_colstack(colstack_no);
+
+ if (!colstack->page_start) {
+ return 1;
+ }
+ if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) {
+ return 2;
+ }
+ return 0;
+}
+
+
+/* stack for \pdfsetmatrix */
+
+typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+} matrix_entry;
+static matrix_entry *matrix_stack = 0;
+static int matrix_stack_size = 0;
+static int matrix_stack_used = 0;
+
+boolean matrixused()
+{
+ return matrix_stack_used > 0;
+}
+
+/* stack for positions of \pdfsave */
+typedef struct {
+ int pos_h;
+ int pos_v;
+ int matrix_stack;
+} pos_entry;
+static pos_entry *pos_stack = 0; /* the stack */
+static int pos_stack_size = 0; /* initially empty */
+static int pos_stack_used = 0; /* used entries */
+
+void matrix_stack_room()
+{
+ matrix_entry *new_stack;
+
+ if (matrix_stack_used >= matrix_stack_size) {
+ matrix_stack_size += STACK_INCREMENT;
+ new_stack = xtalloc(matrix_stack_size, matrix_entry);
+ memcpy((void *) new_stack, (void *) matrix_stack,
+ matrix_stack_used * sizeof(matrix_entry));
+ xfree(matrix_stack);
+ matrix_stack = new_stack;
+ }
+}
+
+void checkpdfsave(int cur_h, int cur_v)
+{
+ pos_entry *new_stack;
+
+ if (pos_stack_used >= pos_stack_size) {
+ pos_stack_size += STACK_INCREMENT;
+ new_stack = xtalloc(pos_stack_size, pos_entry);
+ memcpy((void *) new_stack, (void *) pos_stack,
+ pos_stack_used * sizeof(pos_entry));
+ xfree(pos_stack);
+ pos_stack = new_stack;
+ }
+ pos_stack[pos_stack_used].pos_h = cur_h;
+ pos_stack[pos_stack_used].pos_v = cur_v;
+ if (page_mode) {
+ pos_stack[pos_stack_used].matrix_stack = matrix_stack_used;
+ }
+ pos_stack_used++;
+}
+
+void checkpdfrestore(int cur_h, int cur_v)
+{
+ int diff_h, diff_v;
+ if (pos_stack_used == 0) {
+ pdftex_warn("%s", "\\pdfrestore: missing \\pdfsave");
+ return;
+ }
+ pos_stack_used--;
+ diff_h = cur_h - pos_stack[pos_stack_used].pos_h;
+ diff_v = cur_v - pos_stack[pos_stack_used].pos_v;
+ if (diff_h != 0 || diff_v != 0) {
+ pdftex_warn("Misplaced \\pdfrestore by (%usp, %usp)", diff_h, diff_v);
+ }
+ if (page_mode) {
+ matrix_stack_used = pos_stack[pos_stack_used].matrix_stack;
+ }
+}
+
+void pdfshipoutbegin(boolean shipping_page)
+{
+ pos_stack_used = 0; /* start with empty stack */
+
+ page_mode = shipping_page;
+ if (shipping_page) {
+ colorstackpagestart();
+ }
+}
+
+void pdfshipoutend(boolean shipping_page)
+{
+ if (pos_stack_used > 0) {
+ pdftex_warn("%u unmatched \\pdfsave after %s shipout",
+ (unsigned int) pos_stack_used,
+ ((shipping_page) ? "page" : "form"));
+ }
+}
+
+/*
+ \pdfsetmatrix{a b c d}
+ e := cur_h
+ f := cur_v
+ M_top: current active matrix at the top of
+ the matrix stack
+
+ The origin of \pdfsetmatrix is the current point.
+ The annotation coordinate system is the original
+ page coordinate system. When pdfTeX calculates
+ annotation rectangles it does not take into
+ account this transformations, it uses the original
+ coordinate system. To get the corrected values,
+ first we go back to the origin, perform the
+ transformation and go back:
+
+ ( 1 0 0 ) ( a b 0 ) ( 1 0 0 )
+ ( 0 1 0 ) x ( c d 0 ) x ( 0 1 0 ) x M_top
+ ( -e -f 1 ) ( 0 0 1 ) ( e f 1 )
+
+ ( 1 0 0 ) ( a b 0 )
+ = ( 0 1 0 ) x ( c d 0 ) x M_top
+ ( e f 1 ) ( -e -f 1 )
+
+ ( a b 0 )
+ = ( c d 0 ) x M_top
+ ( e(1-a)-fc f(1-d)-eb 1 )
+
+*/
+
+void pdfsetmatrix(poolpointer in, scaled cur_h, scaled cur_v)
+{
+ /* Argument of \pdfsetmatrix starts with strpool[in] and ends
+ before strpool[poolptr]. */
+
+ matrix_entry x, *y, *z;
+
+ if (page_mode) {
+ if (sscanf((const char *) &strpool[in], " %lf %lf %lf %lf ",
+ &x.a, &x.b, &x.c, &x.d) != 4) {
+ pdftex_warn("Unrecognized format of \\pdfsetmatrix{%s}",
+ &strpool[poolptr]);
+ return;
+ }
+ /* calculate this transformation matrix */
+ x.e = (double) cur_h *(1.0 - x.a) - (double) cur_v *x.c;
+ x.f = (double) cur_v *(1.0 - x.d) - (double) cur_h *x.b;
+ matrix_stack_room();
+ z = &matrix_stack[matrix_stack_used];
+ if (matrix_stack_used > 0) {
+ y = &matrix_stack[matrix_stack_used - 1];
+ z->a = x.a * y->a + x.b * y->c;
+ z->b = x.a * y->b + x.b * y->d;
+ z->c = x.c * y->a + x.d * y->c;
+ z->d = x.c * y->b + x.d * y->d;
+ z->e = x.e * y->a + x.f * y->c + y->e;
+ z->f = x.e * y->b + x.f * y->d + y->f;
+ } else {
+ z->a = x.a;
+ z->b = x.b;
+ z->c = x.c;
+ z->d = x.d;
+ z->e = x.e;
+ z->f = x.f;
+ }
+ matrix_stack_used++;
+ }
+}
+
+/* Apply matrix to point (x,y)
+
+ ( a b 0 )
+ ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 )
+ ( e f 1 )
+
+ If \pdfsetmatrix wasn't used, then return the value unchanged.
+*/
+
+/* Return valeus for matrix tranform functions */
+static scaled ret_llx;
+static scaled ret_lly;
+static scaled ret_urx;
+static scaled ret_ury;
+
+scaled getllx()
+{
+ return ret_llx;
+}
+
+scaled getlly()
+{
+ return ret_lly;
+}
+
+scaled geturx()
+{
+ return ret_urx;
+}
+
+scaled getury()
+{
+ return ret_ury;
+}
+
+static int last_llx;
+static int last_lly;
+static int last_urx;
+static int last_ury;
+
+#define DO_ROUND(x) ((x > 0) ? (x + .5) : (x - .5))
+#define DO_MIN(a, b) ((a < b) ? a : b)
+#define DO_MAX(a, b) ((a > b) ? a : b)
+
+void do_matrixtransform(scaled x, scaled y, scaled * retx, scaled * rety)
+{
+ matrix_entry *m = &matrix_stack[matrix_stack_used - 1];
+ double x_old = x;
+ double y_old = y;
+ double x_new = x_old * m->a + y_old * m->c + m->e;
+ double y_new = x_old * m->b + y_old * m->d + m->f;
+ *retx = (scaled) DO_ROUND(x_new);
+ *rety = (scaled) DO_ROUND(y_new);
+}
+
+void matrixtransformrect(scaled llx, scaled lly, scaled urx, scaled ury)
+{
+ scaled x1, x2, x3, x4, y1, y2, y3, y4;
+
+ if (page_mode && matrix_stack_used > 0) {
+ last_llx = llx;
+ last_lly = lly;
+ last_urx = urx;
+ last_ury = ury;
+ do_matrixtransform(llx, lly, &x1, &y1);
+ do_matrixtransform(llx, ury, &x2, &y2);
+ do_matrixtransform(urx, lly, &x3, &y3);
+ do_matrixtransform(urx, ury, &x4, &y4);
+ ret_llx = DO_MIN(DO_MIN(x1, x2), DO_MIN(x3, x4));
+ ret_lly = DO_MIN(DO_MIN(y1, y2), DO_MIN(y3, y4));
+ ret_urx = DO_MAX(DO_MAX(x1, x2), DO_MAX(x3, x4));
+ ret_ury = DO_MAX(DO_MAX(y1, y2), DO_MAX(y3, y4));
+ } else {
+ ret_llx = llx;
+ ret_lly = lly;
+ ret_urx = urx;
+ ret_ury = ury;
+ }
+}
+
+void matrixtransformpoint(scaled x, scaled y)
+{
+ if (page_mode && matrix_stack_used > 0) {
+ do_matrixtransform(x, y, &ret_llx, &ret_lly);
+ } else {
+ ret_llx = x;
+ ret_lly = y;
+ }
+}
+
+void matrixrecalculate(scaled urx)
+{
+ matrixtransformrect(last_llx, last_lly, urx, last_ury);
+}
+
+void allocvffnts(void)
+{
+ if (vf_e_fnts_array == NULL) {
+ vf_e_fnts_array = vfefnts;
+ vf_e_fnts_limit = fontmax;
+ vf_e_fnts_ptr = vf_e_fnts_array;
+ vf_i_fnts_array = vfifnts;
+ vf_i_fnts_limit = fontmax;
+ vf_i_fnts_ptr = vf_i_fnts_array;
+ }
+ alloc_array(vf_e_fnts, 1, fontmax);
+ vf_e_fnts_ptr++;
+ alloc_array(vf_i_fnts, 1, fontmax);
+ vf_i_fnts_ptr++;
+ if (vf_e_fnts_array != vfefnts) {
+ vfefnts = vf_e_fnts_array;
+ vfifnts = vf_i_fnts_array;
+ }
+}