diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/web2c/pdftexdir/utils.c | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir/utils.c')
-rw-r--r-- | Build/source/texk/web2c/pdftexdir/utils.c | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/utils.c b/Build/source/texk/web2c/pdftexdir/utils.c new file mode 100644 index 00000000000..c1be283ba2e --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/utils.c @@ -0,0 +1,1129 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +pdfTeX is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +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 $ +*/ + +#include "sys/types.h" +#include "regex.h" +#include "ptexlib.h" +#include "zlib.h" +#include "md5.h" +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/c-stat.h> +#include <kpathsea/c-fopen.h> +#include <time.h> + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#25 $"; + +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 */ + +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 char_ptr, char_array & char_limit */ +typedef char char_entry; +define_array(char); + +integer fb_offset(void) +{ + return fb_ptr - fb_array; +} + +void fb_seek(integer offset) +{ + fb_ptr = fb_array + offset; +} + +void fb_putchar(eightbits b) +{ + alloc_array(fb, 1, SMALL_ARRAY_SIZE); + *fb_ptr++ = b; +} + +void fb_flush(void) +{ + fb_entry *p; + integer n; + for (p = fb_array; p < fb_ptr;) { + n = pdfbufsize - pdfptr; + if (fb_ptr - p < n) + n = fb_ptr - p; + memcpy(pdfbuf + pdfptr, p, (unsigned)n); + pdfptr += n; + if (pdfptr == pdfbufsize) + pdfflush(); + p += n; + } + 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); +} + +void make_subset_tag(fm_entry *fm_cur, char **glyph_names) +{ + 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]); + } + 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; + } + tag[6] = 0; + fm_cur->subset_tag = xstrdup(tag); +} + +void pdf_puts(const char *s) +{ + pdfroom(strlen(s) + 1); + while (*s) + pdfbuf[pdfptr++] = *s++; +} + +void pdf_printf(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + vsprintf(print_buf, fmt, args); + pdf_puts(print_buf); + va_end(args); +} + +strnumber maketexstring(const char *s) +{ + int l; + if (s == NULL || *s == 0) + return getnullstr(); + l = strlen(s); + check_buf(poolptr + l, poolsize); + while (l-- > 0) + strpool[poolptr++] = *s++; + last_tex_string = makestring(); + return last_tex_string; +} + +void tex_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vsprintf(print_buf, fmt, args); + print(maketexstring(print_buf)); + flushstr(last_tex_string); + xfflush(stdout); + va_end(args); +} + +/* Helper for pdftex_fail. */ +static void safe_print(const char *str) +{ + const char *c; + for (c = str; *c; ++c) + print(*c); +} + +/* 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,...) +{ + va_list args; + va_start(args, fmt); + println(); + safe_print("Error: "); + safe_print(program_invocation_name); + if (cur_file_name) { + safe_print(" (file "); + safe_print(cur_file_name); + safe_print(")"); + } + safe_print(": "); + vsprintf(print_buf, fmt, args); + safe_print(print_buf); + va_end(args); + println(); + safe_print(" ==> Fatal error occurred, the output PDF file is not finished!"); + println(); + exit(-1); +} + +void pdftex_warn(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + println(); + tex_printf("Warning: %s", program_invocation_name); + if (cur_file_name) + tex_printf(" (file %s)", cur_file_name); + tex_printf(": "); + vsprintf(print_buf, fmt, args); + print(maketexstring(print_buf)); + flushstr(last_tex_string); + va_end(args); + println(); +} + +char *makecstring(integer s) +{ + static char cstrbuf[MAX_CSTRING_LEN]; + char *p = cstrbuf; + int i, l = strstart[s + 1] - strstart[s]; + check_buf(l + 1, MAX_CSTRING_LEN); + 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) +{ + char *name_string, *format_string, *s; + + 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); + /* 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); + job_id_string = xstrdup(s); + xfree(s); + xfree(name_string); + xfree(format_string); +} + +void makepdftexbanner(void) +{ + static boolean pdftexbanner_init = false; + char *s; + + if (pdftexbanner_init) + return; + + s = xtalloc(SMALL_BUF_SIZE + + strlen(ptexbanner) + + strlen(versionstring) + + strlen(kpathsea_version_string), char); + /* The Web2c version string starts with a space. */ + sprintf(s, "%s%s %s", ptexbanner, versionstring, kpathsea_version_string); + pdftexbanner = maketexstring(s); + xfree(s); + pdftexbanner_init = true; +} + +strnumber getresnameprefix(void) +{ +/* static char name_str[] = */ +/* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */ +/* "^_`abcdefghijklmnopqrstuvwxyz|~"; */ + static char name_str[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + char prefix[7]; /* make a tag of 6 chars long */ + unsigned long crc; + int i, base = strlen(name_str); + crc = crc32(0L, Z_NULL, 0); + 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; + } + prefix[6] = 0; + return maketexstring(prefix); +} + +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) +{ + if (fflush(stream) != 0) + pdftex_fail("fflush() failed"); + return 0; +} + +int xgetc(FILE *stream) +{ + int c = getc(stream); + if (c < 0 && c != EOF) + pdftex_fail("getc() failed"); + return c; +} + +int xputc(int c, FILE *stream) +{ + int i = putc(c, stream); + if (i < 0) + pdftex_fail("putc() failed"); + return i; +} + +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); +} + +scaled extxnoverd(scaled x, scaled n, scaled d) +{ + double r = (((double)x)*((double)n))/((double)d); + if (r > 0) + r += 0.5; + else + r -= 0.5; + if (r >= (double)maxinteger || r <= -(double)maxinteger) + pdftex_warn("arithmetic: number too big"); + return r; +} + +void libpdffinish() +{ + xfree(fb_array); + xfree(char_array); + xfree(job_id_string); + fm_free(); + t1_free(); + enc_free(); + img_free(); + vf_free(); + epdf_free(); +} + +/* Converts any string given in in in an allowed PDF string which can be + * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and + * control characters are octal encoded. + * This assumes that the string does not contain any already escaped + * characters! + */ +char *convertStringToPDFString (char *in, int len) +{ + static char pstrbuf[MAX_PSTRING_LEN]; + char *out = pstrbuf; + int i, j; + 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] > '~')){ + /* convert control characters into oct */ + sprintf (buf, "\\%03o", (unsigned int)(unsigned char)in[i]); + out[j++] = buf[0]; + out[j++] = buf[1]; + out[j++] = buf[2]; + out[j++] = buf[3]; + } + else if ((in[i] == '(') || (in[i] == ')')) { + /* escape paranthesis */ + out[j++] = '\\'; + out[j++] = in[i]; + } + else if (in[i] == '\\') { + /* escape backslash */ + out[j++] = '\\'; + out[j++] = '\\'; + } + else { + /* copy char :-) */ + out[j++] = in[i]; + } + } + out[j] = '\0'; + return pstrbuf; +} + + +/* Converts any string given in in in an allowed PDF string which can be + * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and + * control characters are octal encoded. + * This assumes that the string does not contain any already escaped + * characters! + * + * See escapename for parameter description. + */ +void escapestring(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch; + while (in < out) { + if (poolptr + 4 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch < '!') || (ch > '~')) { + /* convert control characters into oct */ + sprintf (&strpool[poolptr], "\\%.3o", (unsigned int)ch); + poolptr += 4; + continue; + } + if ((ch == '(') || (ch == ')') || (ch == '\\')) { + /* escape parenthesis and backslash */ + strpool[poolptr++] = '\\'; + } + /* copy char :-) */ + strpool[poolptr++] = ch; + } +} + + +/* 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 + be included in a name by writing its 2-digit hexadecimal code, preceded + by the number sign character (#); see implementation notes 3 and 4 in + Appendix H. This syntax is required to represent any of the delimiter or + white-space characters or the number sign character itself; it is + recommended but not required for characters whose codes are outside the + range 33 (!) to 126 (~). + </blockquote> + The following table shows the conversion that are done by this + function: + code result reason + ----------------------------------- + 0 ignored not allowed + 1..32 escaped must for white-space: + 9 (tab), 10 (lf), 12 (ff), 13 (cr), 32 (space) + recommended for the other control characters + 35 escaped escape char "#" + 37 escaped delimiter "%" + 40..41 escaped delimiters "(" and ")" + 47 escaped delimiter "/" + 60 escaped delimiter "<" + 62 escaped delimiter ">" + 91 escaped delimiter "[" + 93 escaped delimiter "]" + 123 escaped delimiter "{" + 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. + Thus at the begin of the procedure the global variable + "poolptr" points to the start of the output string and + after the end when the procedure returns. +*/ +void escapename(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch; + + while (in < out) { + if (poolptr + 3 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch >= 1 && ch <= 32) || ch >= 127) { + /* escape */ + sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch); + poolptr += 3; + continue; + } + switch (ch) { + case 0: + /* ignore */ + break; + case 35: + case 37: + case 40: + case 41: + case 47: + case 60: + case 62: + case 91: + case 93: + case 123: + case 125: + /* escape */ + sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch); + poolptr += 3; + break; + default: + /* copy */ + strpool[poolptr++] = ch; + } + } +} + +/* 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; + unsigned char ch; + + while (in < out) { + if (poolptr + 2 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + sprintf(&strpool[poolptr], "%.2X", (unsigned int)ch); + poolptr += 2; + } +} + +/* Unescape any given hexadecimal string. + + 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; + boolean first = true; + + while (in < out) { + if (poolptr + 1 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch >= '0') && (ch <= '9')) { + ch -= '0'; + } + else if ((ch >= 'A') && (ch <= 'F')) { + ch -= 'A' - 10; + } + else if ((ch >= 'a') && (ch <= 'f')) { + ch -= 'a' - 10; + } + 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 */ + strpool[poolptr++] = ch << 4; + } +} + + +/* 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) +{ + int i, j; + char buf[3]; + j = 0; + for (i = 0; i < lin; i++) { + sprintf (buf, "%02X", (unsigned int)(unsigned char)in[i]); + out[j++] = buf[0]; + out[j++] = buf[1]; + } + out[j] = '\0'; +} + +/* Compute the ID string as per PDF1.4 9.3: + <blockquote> + File identifers are defined by the optional ID entry in a PDF file's + trailer dictionary (see Section 3.4.4, "File Trailer"; see also + implementation note 105 in Appendix H). The value of this entry is an + array of two strings. The first string is a permanent identifier based + on the contents of the file at the time it was originally created, and + does not change when the file is incrementally updated. The second + string is a changing identifier based on the file's contents at the + time it was last updated. When a file is first written, both + 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. + 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 + - The values of all entries in the file's document information + dictionary (see Section 9.2.1, Document Information Dictionary ) + </blockquote> + This stipulates only that the two IDs must be identical when the file is + created and that they should be reasonably unique. Since it's difficult + to get the file size at this point in the execution of pdfTeX and + scanning the info dict is also difficult, we start with a simpler + implementation using just the first two items. + */ +void printID (strnumber filename) +{ + time_t t; + size_t size; + char time_str[32]; + md5_state_t state; + md5_byte_t digest[16]; + char id[64]; + char *file_name; + char pwd[4096]; + /* start md5 */ + 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); + /* 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)); + /* finish md5 */ + md5_finish(&state, digest); + /* write the IDs */ + convertStringToHexString ((char*)digest, id, 16); + pdf_printf("/ID [<%s> <%s>]", id, id); +} + +/* Print the /CreationDate entry. + + PDF Reference, third edition says about the expected date format: + <blockquote> + 3.8.2 Dates + + PDF defines a standard date format, which closely follows that of + the international standard ASN.1 (Abstract Syntax Notation One), + defined in ISO/IEC 8824 (see the Bibliography). A date is a string + of the form + + (D:YYYYMMDDHHmmSSOHH'mm') + + where + + YYYY is the year + MM is the month + DD is the day (01-31) + HH is the hour (00-23) + mm is the minute (00-59) + SS is the second (00-59) + O is the relationship of local time to Universal Time (UT), + denoted by one of the characters +, -, or Z (see below) + HH followed by ' is the absolute value of the offset from UT + in hours (00-23) + mm followed by ' is the absolute value of the offset from UT + in minutes (00-59) + + The apostrophe character (') after HH and mm is part of the syntax. + All fields after the year are optional. (The prefix D:, although also + optional, is strongly recommended.) The default values for MM and DD + are both 01; all other numerical fields default to zero values. A plus + sign (+) as the value of the O field signifies that local time is + later than UT, a minus sign (-) that local time is earlier than UT, + and the letter Z that local time is equal to UT. If no UT information + is specified, the relationship of the specified time to UT is + considered to be unknown. Whether or not the time zone is known, the + rest of the date should be specified in local time. + + For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard + Time, is represented by the string + + D:199812231952-08'00' + </blockquote> + + 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). +*/ + +time_t start_time = 0; +#define TIME_STR_SIZE 30 +char start_time_str[TIME_STR_SIZE]; +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) +{ + + struct tm lt, gmt; + size_t size; + int 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", <); + /* expected format: "YYYYmmddHHMMSS" */ + if (size == 0) { + /* unexpected, contents of time_str is undefined */ + time_str[0] = '\0'; + return; + } + + /* correction for seconds: %S can be in range 00..61, + 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 */ + } + + /* 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; + if (lt.tm_year != gmt.tm_year) { + off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440; + } + 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); + } +} + +void initstarttime() { + if (start_time == 0) { + start_time = time((time_t *) NULL); + makepdftime(start_time, start_time_str); + } +} + +void printcreationdate() { + initstarttime(); + pdf_printf("/CreationDate (%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); + + initstarttime(); + + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + memcpy(&strpool[poolptr], start_time_str, len); + poolptr += len; +} + +void getfilemoddate(strnumber s) { + struct stat file_data; + + char *file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + + /* get file status */ + if (stat(file_name, &file_data) == 0) { + int len; + + makepdftime(file_data.st_mtime, time_str); + len = strlen(time_str); + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + } + else { + memcpy(&strpool[poolptr], time_str, len); + poolptr += len; + } + } + /* else { errno contains error code } */ + + xfree(file_name); +} + +void getfilesize(strnumber s) { + struct stat file_data; + + char *file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + + /* get file status */ + if (stat(file_name, &file_data) == 0) { + int len; + char buf[20]; + + /* st_size has type off_t */ + sprintf(buf, "%lu", (long unsigned int)file_data.st_size); + len = strlen(buf); + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + } + 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) { + 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 */ + } + /* 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); + } + 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); + } + + if (poolptr + len >= poolsize) { + /* error by str_toks that calls str_room(1) */ + return; + } + convertStringToHexString((char*)digest, outbuf, DIGEST_SIZE); + memcpy(&strpool[poolptr], outbuf, len); + poolptr += len; +} + +void getfiledump(strnumber s, int offset, int length) { + FILE *f; + int read; + poolpointer data_ptr; + poolpointer data_end; + char *file_name; + + if (length == 0) { + /* 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 */ + } + + /* 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) { + 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. */ + data_ptr = poolptr + length; + 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; + } + 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; + +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); + str = xtalloc(size, char); + regerror(ret, &preg, str, size); + pdftex_warn("%s%s", "\\pdfmatch: ", str); + xfree(str); + strpool[poolptr++] = '-'; + strpool[poolptr++] = '1'; + } + else { + str = makecstring(t); + sub_match_count = ((subcount < 0) ? + DEFAULT_SUB_MATCH_COUNT : subcount); + xfree(pmatch); + if (sub_match_count > 0) { + 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'; + } + } + + regfree(&preg); +} + +void getmatch(int i) { + int size = 0; + int len = 0; + + boolean found = i < sub_match_count + && 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 { + size = 4; + } + + if (poolptr + size >= poolsize) { + poolptr = poolsize; + return; + } + + if (found) { + sprintf(&strpool[poolptr], "%d", pmatch[i].rm_so); + poolptr += strlen(&strpool[poolptr]); + strpool[poolptr++] = '-'; + strpool[poolptr++] = '>'; + memcpy(&strpool[poolptr], &match_string[pmatch[i].rm_so], len); + poolptr += len; + return; + } + + strpool[poolptr++] = '-'; + strpool[poolptr++] = '1'; + strpool[poolptr++] = '-'; + strpool[poolptr++] = '>'; +} + + +/* makecfilename + input/ouput same as makecstring: + input: string number + output: C string with quotes removed. +*/ +char *makecfilename(strnumber s) { + char *name = makecstring(s); + char *p = name; + char *q = name; + + while (*p) { + if (*p != '"') + *q++ = *p; + p++; + } + *q = '\0'; + fprintf(stderr, " %s\n", name); + return name; +} |