Back to index

tetex-bin  3.0
utils.c
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 1996-2003 Han The Thanh, <thanh@pdftex.org>
00003 
00004 This file is part of pdfTeX.
00005 
00006 pdfTeX is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2 of the License, or
00009 (at your option) any later version.
00010 
00011 pdfTeX is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with pdfTeX; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#21 $
00021 */
00022 
00023 #include "ptexlib.h"
00024 #include "zlib.h"
00025 #include "md5.h"
00026 #include <kpathsea/c-vararg.h>
00027 #include <kpathsea/c-proto.h>
00028 #include <time.h>
00029 
00030 static const char perforce_id[] = 
00031     "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#21 $";
00032 
00033 char *cur_file_name = NULL;
00034 strnumber last_tex_string;
00035 static char print_buf[PRINTF_BUF_SIZE];
00036 static char *jobname_cstr = NULL;
00037 static char *job_id_string = NULL;
00038 static char *escaped_string = NULL;
00039 extern string ptexbanner; /* from web2c/lib/texmfmp.c */
00040 extern string versionstring; /* from web2c/lib/version.c */         
00041 extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */
00042 
00043 size_t last_ptr_index; /* for use with alloc_array */
00044 
00045 /* define fb_ptr, fb_array & fb_limit */
00046 typedef char fb_entry;
00047 define_array(fb);   
00048 
00049 /* define char_ptr, char_array & char_limit */
00050 typedef char char_entry;
00051 define_array(char);   
00052 
00053 integer fb_offset(void)
00054 {
00055     return fb_ptr - fb_array;
00056 }
00057 
00058 void fb_seek(integer offset)
00059 {
00060      fb_ptr = fb_array + offset;
00061 }
00062 
00063 void fb_putchar(eightbits b)
00064 {
00065     alloc_array(fb, 1, SMALL_ARRAY_SIZE);
00066     *fb_ptr++ = b;
00067 }
00068 
00069 void fb_flush(void)
00070 {
00071     fb_entry *p;
00072     integer n;
00073     for (p = fb_array; p < fb_ptr;) {
00074         n = pdfbufsize - pdfptr;
00075         if (fb_ptr - p < n)
00076             n = fb_ptr - p;
00077         memcpy(pdfbuf + pdfptr, p, (unsigned)n);
00078         pdfptr += n;
00079         if (pdfptr == pdfbufsize)
00080             pdfflush();
00081         p += n;
00082     }
00083     fb_ptr = fb_array;
00084 }
00085 
00086 static void fnstr_append(const char *s)
00087 {
00088     int l = strlen(s) + 1;
00089     alloc_array(char, l, SMALL_ARRAY_SIZE);
00090     strcat(char_ptr, s);
00091     char_ptr = strend(char_ptr);
00092 }
00093 
00094 void make_subset_tag(fm_entry *fm_cur, char **glyph_names)
00095 {
00096     char tag[7];
00097     unsigned long crc;
00098     int i, l = strlen(job_id_string) + 1;
00099     alloc_array(char, l, SMALL_ARRAY_SIZE);
00100     strcpy(char_array, job_id_string);
00101     char_ptr = strend(char_array);
00102     if (fm_cur->tfm_name != NULL) {
00103         fnstr_append(" TFM name: ");
00104         fnstr_append(fm_cur->tfm_name);
00105     }
00106     fnstr_append(" PS name: ");
00107     if (font_keys[FONTNAME_CODE].valid)
00108         fnstr_append(fontname_buf);
00109     else if (fm_cur->ps_name != NULL)
00110         fnstr_append(fm_cur->ps_name);
00111     fnstr_append(" Encoding: ");
00112     if (fm_cur->encoding != NULL && (fm_cur->encoding)->name != NULL)
00113         fnstr_append((fm_cur->encoding)->name);
00114     else
00115         fnstr_append("built-in");
00116     fnstr_append(" CharSet: ");
00117     assert(glyph_names != NULL);
00118     for (i = 0; i <= MAX_CHAR_CODE; i++)
00119         if (pdfcharmarked(tex_font, i) && glyph_names[i] != notdef) {
00120             fnstr_append(" /");
00121             fnstr_append(glyph_names[i]);
00122         }
00123     if (fm_cur->charset != NULL) {
00124         fnstr_append(" Extra CharSet: ");
00125         fnstr_append(fm_cur->charset);
00126     }
00127     crc = crc32(0L, Z_NULL, 0);
00128     crc = crc32(crc, (Bytef*)char_array, strlen(char_array));
00129     /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
00130      * there are 26 uppercase chars ==> each char represents a number in range
00131      * 0..25. The maximal number that can be represented by the tag is
00132      * 26^6 - 1, which is a number between 2^28 and 2^29. Thus the bits 29..31
00133      * of the CRC must be dropped out.
00134      */
00135     for (i = 0; i < 6; i++) {
00136         tag[i] = 'A' + crc % 26;
00137         crc /= 26;
00138     }
00139     tag[6] = 0;
00140     fm_cur->subset_tag = xstrdup(tag);
00141 }
00142 
00143 void pdf_puts(const char *s)
00144 {
00145     pdfroom(strlen(s) + 1);
00146     while (*s)
00147         pdfbuf[pdfptr++] = *s++;
00148 }
00149 
00150 void pdf_printf(const char *fmt,...)
00151 {
00152     va_list args;
00153     va_start(args, fmt);
00154     vsprintf(print_buf, fmt, args);
00155     pdf_puts(print_buf);                                    
00156     va_end(args);
00157 }
00158 
00159 strnumber maketexstring(const char *s)
00160 {
00161     int l;
00162     if (s == NULL || *s == 0)
00163         return getnullstr();
00164     l = strlen(s);
00165     check_buf(poolptr + l, poolsize);
00166     while (l-- > 0)
00167         strpool[poolptr++] = *s++;
00168     last_tex_string = makestring();
00169     return last_tex_string;
00170 }
00171 
00172 void tex_printf(const char *fmt, ...)
00173 {
00174     va_list args;
00175     va_start(args, fmt);
00176     vsprintf(print_buf, fmt, args);
00177     print(maketexstring(print_buf));
00178     flushstr(last_tex_string);
00179     xfflush(stdout);
00180     va_end(args);
00181 }
00182 
00183 /* Helper for pdftex_fail. */
00184 static void safe_print(const char *str)
00185 {
00186     const char *c;
00187     for (c = str; *c; ++c)
00188         print(*c);
00189 }
00190 
00191 /* pdftex_fail may be called when a buffer overflow has happened/is
00192    happening, therefore may not call mktexstring.  However, with the
00193    current implementation it appears that error messages are misleading,
00194    possibly because pool overflows are detected too late. */
00195 void pdftex_fail(const char *fmt,...)
00196 {
00197     va_list args;
00198     va_start(args, fmt);
00199     println();
00200     safe_print("Error: ");
00201     safe_print(program_invocation_name);
00202     if (cur_file_name) {
00203         safe_print(" (file ");
00204         safe_print(cur_file_name);
00205         safe_print(")");
00206     }
00207     safe_print(": ");
00208     vsprintf(print_buf, fmt, args);
00209     safe_print(print_buf);
00210     va_end(args);
00211     println();
00212     safe_print(" ==> Fatal error occurred, the output PDF file is not finished!");
00213     println();
00214     exit(-1);
00215 }
00216 
00217 void pdftex_warn(const char *fmt,...)
00218 {
00219     va_list args;
00220     va_start(args, fmt);
00221     println();
00222     tex_printf("Warning: %s", program_invocation_name);
00223     if (cur_file_name)
00224         tex_printf(" (file %s)", cur_file_name);
00225     tex_printf(": ");
00226     vsprintf(print_buf, fmt, args);
00227     print(maketexstring(print_buf));
00228     flushstr(last_tex_string);
00229     va_end(args);
00230     println();
00231 }
00232 
00233 char *makecstring(integer s)
00234 {
00235     static char cstrbuf[MAX_CSTRING_LEN];
00236     char *p = cstrbuf;
00237     int i, l = strstart[s + 1] - strstart[s];
00238     check_buf(l + 1, MAX_CSTRING_LEN);
00239     for (i = 0; i < l; i++)
00240         *p++ = strpool[i + strstart[s]];
00241     *p = 0;
00242     return cstrbuf;
00243 }
00244 
00245 /*
00246 boolean str_eq_cstr(strnumber n, char *s)
00247 {
00248     int l;
00249     if (s == NULL || n == 0)
00250         return false;
00251     l = strstart[n];
00252     while (*s && l < strstart[n + 1] && *s == strpool[l])
00253         l++, s++;
00254     return !*s && l == strstart[n + 1];
00255 }
00256 */
00257 
00258 void setjobid(int year, int month, int day, int time, int pdftexversion, int pdftexrevision)
00259 {
00260     char *name_string, *format_string, *s;
00261 
00262     if (job_id_string != NULL)
00263         return;
00264 
00265     name_string = xstrdup(makecstring(jobname));
00266     format_string = xstrdup(makecstring(formatident));
00267     s = xtalloc(SMALL_BUF_SIZE + 
00268                 strlen(name_string) + 
00269                 strlen(format_string) + 
00270                 strlen(ptexbanner) + 
00271                 strlen(versionstring) + 
00272                 strlen(kpathsea_version_string), char);
00273     /* The Web2c version string starts with a space.  */
00274     sprintf(s, "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s",
00275             year, month, day, time/60, time%60, 
00276             name_string, format_string, ptexbanner, 
00277             versionstring, kpathsea_version_string);
00278     job_id_string = xstrdup(s);
00279     xfree(s);
00280     xfree(name_string);
00281     xfree(format_string);
00282 }
00283 
00284 void makepdftexbanner(void)
00285 {
00286     static boolean pdftexbanner_init = false;
00287     char *s;
00288 
00289     if (pdftexbanner_init)
00290         return;
00291 
00292     s = xtalloc(SMALL_BUF_SIZE + 
00293                 strlen(ptexbanner) + 
00294                 strlen(versionstring) + 
00295                 strlen(kpathsea_version_string), char);
00296     /* The Web2c version string starts with a space.  */
00297     sprintf(s, "%s%s %s", ptexbanner, versionstring, kpathsea_version_string);
00298     pdftexbanner = maketexstring(s);
00299     xfree(s);
00300     pdftexbanner_init = true;
00301 }
00302 
00303 strnumber getresnameprefix(void)
00304 {
00305 /*     static char name_str[] = */
00306 /* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */
00307 /* "^_`abcdefghijklmnopqrstuvwxyz|~"; */
00308     static char name_str[] =
00309 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00310     char prefix[7]; /* make a tag of 6 chars long */
00311     unsigned long crc;
00312     int i, base = strlen(name_str);
00313     crc = crc32(0L, Z_NULL, 0);
00314     crc = crc32(crc, (Bytef*)job_id_string, strlen(job_id_string));
00315     for (i = 0; i < 6; i++) {
00316         prefix[i] = name_str[crc % base];
00317         crc /= base;
00318     }
00319     prefix[6] = 0;
00320     return maketexstring(prefix);
00321 }
00322 
00323 size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
00324 {
00325     if (fwrite(ptr, size, nmemb, stream) != nmemb)
00326         pdftex_fail("fwrite() failed");
00327     return nmemb;
00328 }
00329 
00330 int xfflush(FILE *stream)
00331 {
00332     if (fflush(stream) != 0)
00333         pdftex_fail("fflush() failed");
00334     return 0;
00335 }
00336 
00337 int xgetc(FILE *stream)
00338 {
00339     int c = getc(stream);
00340     if (c < 0 && c != EOF)
00341         pdftex_fail("getc() failed");
00342     return c;
00343 }
00344 
00345 int xputc(int c, FILE *stream)
00346 {
00347     int i = putc(c, stream);
00348     if (i < 0)
00349         pdftex_fail("putc() failed");
00350     return i;
00351 }
00352 
00353 void writestreamlength(integer length, integer offset)
00354 {
00355     integer save_offset;
00356     if (jobname_cstr == NULL)
00357         jobname_cstr = xstrdup(makecstring(jobname));
00358     save_offset = xftell(pdffile, jobname_cstr);
00359     xfseek(pdffile, offset, SEEK_SET, jobname_cstr);
00360     fprintf(pdffile, "%li", (long int)length);
00361     xfseek(pdffile, pdfoffset(), SEEK_SET, jobname_cstr);
00362 }
00363 
00364 scaled extxnoverd(scaled x, scaled n, scaled d)
00365 {
00366     double r = (((double)x)*((double)n))/((double)d);
00367     if (r > 0)
00368         r += 0.5;
00369     else
00370         r -= 0.5;
00371     if (r >= (double)maxinteger || r <= -(double)maxinteger)
00372         pdftex_warn("arithmetic: number too big");
00373     return r;
00374 }
00375 
00376 void libpdffinish()
00377 {
00378     xfree(fb_array);
00379     xfree(char_array);
00380     xfree(job_id_string);
00381     fm_free();
00382     t1_free();
00383     enc_free();
00384     img_free();
00385     vf_free();
00386     epdf_free();
00387 }
00388 
00389 /* Converts any string given in in in an allowed PDF string which can be
00390  * handled by printf et.al.: \ is escaped to \\, paranthesis are escaped and
00391  * control characters are hexadecimal encoded.
00392  */
00393 char *convertStringToPDFString (char *in)
00394 {
00395     static char pstrbuf[MAX_PSTRING_LEN];
00396     char *out = pstrbuf;
00397     int lin = strlen (in);
00398     int i, j;
00399     char buf[4];
00400     j = 0;
00401     for (i = 0; i < lin; i++) {
00402         check_buf(j + sizeof(buf), MAX_PSTRING_LEN);
00403         if ((unsigned char)in[i] < ' ') {
00404             /* convert control characters into hex */
00405             sprintf (buf, "#%02x", (unsigned int)(unsigned char)in[i]);
00406             out[j++] = buf[0];
00407             out[j++] = buf[1];
00408             out[j++] = buf[2];
00409             }
00410         else if ((in[i] == '(') || (in[i] == ')')) {
00411             /* escape paranthesis */
00412             out[j++] = '\\';
00413             out[j++] = in[i];
00414             }
00415         else if (in[i] == '\\') {
00416             /* escape backslash */
00417             out[j++] = '\\';
00418             out[j++] = '\\';
00419             }
00420         else {
00421             /* copy char :-) */
00422             out[j++] = in[i];
00423             }
00424         }
00425     out[j] = '\0';
00426     return pstrbuf;
00427 }
00428 
00429 /* Converts any string given in in in an allowed PDF string which is 
00430  * hexadecimal encoded and enclosed in '<' and '>'.
00431  * sizeof(out) should be at least lin*2+3.
00432  */
00433 void convertStringToHexString (char *in, char *out, int lin)
00434 {
00435     int i, j;
00436     char buf[3];
00437     out[0] = '<';
00438     j = 1;
00439     for (i = 0; i < lin; i++) {
00440         sprintf (buf, "%02X", (unsigned int)(unsigned char)in[i]);
00441         out[j++] = buf[0];
00442         out[j++] = buf[1];
00443         }
00444     out[j++] = '>';
00445     out[j] = '\0';
00446 }
00447 
00448 /* Compute the ID string as per PDF1.4 9.3:
00449   <blockquote>
00450     File identifers are defined by the optional ID entry in a PDF file's
00451     trailer dictionary (see Section 3.4.4, "File Trailer"; see also
00452     implementation note 105 in Appendix H). The value of this entry is an
00453     array of two strings. The first string is a permanent identifier based
00454     on the contents of the file at the time it was originally created, and
00455     does not change when the file is incrementally updated. The second
00456     string is a changing identifier based on the file's contents at the
00457     time it was last updated. When a file is first written, both
00458     identifiers are set to the same value. If both identifiers match when a
00459     file reference is resolved, it is very likely that the correct file has
00460     been found; if only the first identifier matches, then a different
00461     version of the correct file has been found. 
00462         To help ensure the uniqueness of file identifiers, it is recommend
00463     that they be computed using a message digest algorithm such as MD5
00464     (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see
00465     the Bibliography), using the following information (see implementation
00466     note 106 in Appendix H): 
00467     - The current time 
00468     - A string representation of the file's location, usually a pathname 
00469     - The size of the file in bytes 
00470     - The values of all entries in the file's document information
00471       dictionary (see Section 9.2.1,  Document Information Dictionary )
00472   </blockquote>
00473   This stipulates only that the two IDs must be identical when the file is
00474   created and that they should be reasonably unique. Since it's difficult
00475   to get the file size at this point in the execution of pdfTeX and
00476   scanning the info dict is also difficult, we start with a simpler
00477   implementation using just the first two items.
00478  */
00479 void printID (strnumber filename)
00480 {
00481     time_t t;
00482     size_t size;
00483     char time_str[32];
00484     md5_state_t state;
00485     md5_byte_t digest[16];
00486     char id[64];
00487     char *file_name;
00488     char pwd[4096];
00489     /* start md5 */
00490     md5_init(&state);
00491     /* get the time */
00492     t = time(NULL);
00493     size = strftime (time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
00494     md5_append(&state, (const md5_byte_t *)time_str, size);
00495     /* get the file name */
00496     if (getcwd(pwd, sizeof(pwd)) == NULL)
00497         pdftex_fail("getcwd() failed (path too long?)");
00498     file_name = makecstring(filename);
00499     md5_append(&state, (const md5_byte_t *)pwd, strlen(pwd));
00500     md5_append(&state, (const md5_byte_t *)"/", 1);
00501     md5_append(&state, (const md5_byte_t *)file_name, strlen(file_name));
00502     /* finish md5 */
00503     md5_finish(&state, digest);
00504     /* write the IDs */
00505     convertStringToHexString ((char*)digest, id, 16);
00506     pdf_printf("/ID [%s %s]\n", id, id);
00507 }
00508 
00509 /* Print the /CreationDate entry.
00510 
00511   PDF Reference, third edition says about the expected date format:
00512   <blockquote>
00513     3.8.2 Dates
00514 
00515       PDF defines a standard date format, which closely follows that of
00516       the international standard ASN.1 (Abstract Syntax Notation One),
00517       defined in ISO/IEC 8824 (see the Bibliography). A date is a string
00518       of the form
00519 
00520         (D:YYYYMMDDHHmmSSOHH'mm')
00521 
00522       where
00523 
00524         YYYY is the year
00525         MM is the month
00526         DD is the day (01-31)
00527         HH is the hour (00-23)
00528         mm is the minute (00-59)
00529         SS is the second (00-59)
00530         O is the relationship of local time to Universal Time (UT),
00531           denoted by one of the characters +, -, or Z (see below)
00532         HH followed by ' is the absolute value of the offset from UT
00533           in hours (00-23)
00534         mm followed by ' is the absolute value of the offset from UT
00535           in minutes (00-59)
00536 
00537       The apostrophe character (') after HH and mm is part of the syntax.
00538       All fields after the year are optional. (The prefix D:, although also
00539       optional, is strongly recommended.) The default values for MM and DD
00540       are both 01; all other numerical fields default to zero values.  A plus
00541       sign (+) as the value of the O field signifies that local time is
00542       later than UT, a minus sign (-) that local time is earlier than UT,
00543       and the letter Z that local time is equal to UT. If no UT information
00544       is specified, the relationship of the specified time to UT is
00545       considered to be unknown. Whether or not the time zone is known, the
00546       rest of the date should be specified in local time.
00547 
00548       For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard
00549       Time, is represented by the string
00550 
00551         D:199812231952-08'00'
00552   </blockquote>
00553 
00554   The main difficulty is get the time zone offset. strftime() does this in ISO
00555   C99 (e.g. newer glibc) with %z, but we have to work with other systems (e.g.
00556   Solaris 2.5). 
00557 */
00558 void printcreationdate()
00559 {
00560             
00561     time_t t;
00562     struct tm lt, gmt;
00563     size_t size;
00564     /* minimum size for time_str is 22: "YYYYmmddHHMMSS+HH'MM'" */
00565     char time_str[40]; /* larger value for safety */
00566     int off, off_hours, off_mins;
00567  
00568     /* get the time */
00569     t = time(NULL);
00570     lt = *localtime(&t);
00571     size = strftime(time_str, sizeof(time_str), "%Y%m%d%H%M%S", &lt);
00572     /* expected format: "YYYYmmddHHMMSS" */
00573     if (size != 14) {
00574         /* An unexpected result of strftime */
00575         pdftex_warn("/CreationDate dropped because of "
00576                     "unexpected result of strftime()");
00577         return;
00578     }
00579 
00580     /* correction for seconds: %S can be in range 00..61,
00581        the PDF reference expects 00..59,   
00582        therefore we map "60" and "61" to "59" */
00583     if (time_str[12] == '6') {
00584         time_str[12] = '5';
00585         time_str[13] = '9'; /* we have checked for size above */
00586     }
00587 
00588     /* get the time zone offset */
00589     gmt = *gmtime(&t);
00590 
00591     /* this calculation method was found in exim's tod.c */
00592     off = 60*(lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
00593     if (lt.tm_year != gmt.tm_year) {
00594         off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440;
00595     }
00596     else if (lt.tm_yday != gmt.tm_yday) {
00597         off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440;
00598     }
00599 
00600     if (off == 0) {
00601         time_str[size++] = 'Z';
00602         time_str[size] = 0;
00603     }
00604     else {
00605         off_hours = off/60;
00606         off_mins = abs(off - off_hours*60);
00607         sprintf(&time_str[size], "%+03i'%02d'", off_hours, off_mins);
00608     }
00609 
00610     /* print result */
00611     pdf_printf("/CreationDate (D:%s)\n", time_str);
00612 }
00613 
00614 void escapestr(strnumber s)
00615 {
00616     escaped_string = convertStringToPDFString(makecstring(s));
00617 }
00618 
00619 integer escapedstrlen()
00620 {
00621     assert(escaped_string != NULL);
00622     return strlen(escaped_string);
00623 }
00624 
00625 ASCIIcode getescapedchar(integer index)
00626 {
00627     if (index < 0 || index >= strlen(escaped_string))
00628         pdftex_fail("getescapedchar(): index out of range");
00629     return escaped_string[index];
00630 }