[NTG-pdftex] Patch CreationDate
Heiko Oberdiek
oberdiek@uni-freiburg.de
Wed, 30 Jul 2003 22:08:11 +0200
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hello,
Patch CreationDate
If /CreationDate is not given by \pdfinfo, then a default is
used by computing the string by the current setting of
\year, \month, and \time.
Problem A:
The time zone is not set. See the discussion in
de.comp.text.tex, "[pdftex] Zeitzone von CreationDate"
Valentin Schwamberger observed that his AR/Windows shows then
the time as GMT.
Problem B:
It is easy to fool pdfTeX:
* Setting \year to a number less or greater than 4 digits.
* Setting \year, \month, \date, \time to invalid numbers,
eg.: \month=13
The result are invalid dates.
The following patch tries to solve these problems:
* Time zone detection by glibc's strftime("%z").
* The current time is used, not \year, \month, ...
Patch files based on 2003/07/30 v1.11a:
utils.c.diff for TeX/texk/web2c/pdftexdir/utils.c
pdftex.ch.diff for TeX/texk/web2c/pdftexdir/pdftex.ch
pdftex.defines.diff for TeX/texk/web2c/pdftexdir/pdftex.defines
Yours sincerely
Heiko <oberdiek@uni-freiburg.de>
--
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="utils.c.diff"
*** utils.c.org Wed Jul 30 21:43:08 2003
--- utils.c Wed Jul 30 21:42:46 2003
***************
*** 473,475 ****
--- 473,644 ----
convertStringToHexString ((char*)digest, id);
pdf_printf("/ID [%s %s]\n", 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 elds 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 elds 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 data. Function strftime()
+ of glibc knows "%z", the manual page says:
+ <blockquote>
+ %z The time-zone as hour offset from GMT. Required to
+ emit RFC822-conformant dates (using "%a, %d %b %Y
+ %H:%M:%S %z"). (GNU)
+ </blockquote>
+ Does this mean that the output of "%z" can have any RFC822-conformant
+ format?
+
+ RFC 822 specifies:
+ <blockquote>
+ 5. DATE AND TIME SPECIFICATION
+
+ 5.1. SYNTAX
+
+ [...]
+
+ zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ ; A:-1; (J not used)
+ ; M:-12; N:+1; Y:+12
+ / ( ("+" / "-") 4DIGIT ) ; Local differential
+ ; hours+min. (HHMM)
+ </blockquote>
+ */
+ void printcreationdate()
+ {
+ time_t t;
+ struct tm *tt;
+ size_t size;
+ char time_str[40];
+ char *zone_str;
+
+ /* get the time */
+ t = time(NULL);
+ tt = localtime(&t);
+ size = strftime(time_str, sizeof(time_str), "%Y%m%d%H%M%S%z", tt);
+ /* expected format: "YYYYmmddHHMMSSzzzzz" */
+
+ /* 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 (zone_str[12] == '6' && zone_str[13] != 0) {
+ zone_str[12] == '5';
+ zone_str[13] == '9';
+ }
+
+ /* correction for time zone */
+ zone_str = &time_str[14];
+ if ((zone_str[0] == '+' || zone_str[0] == '-') &&
+ isdigit(zone_str[1]) &&
+ isdigit(zone_str[2]) &&
+ isdigit(zone_str[3]) &&
+ isdigit(zone_str[4]) &&
+ zone_str[5] == 0) {
+ /* test for GMT */
+ if (strcmp(&zone_str[1], "0000") == 0) {
+ /* case "+0000" or "-0000" */
+ zone_str[0] = 'Z';
+ zone_str[1] = 0;
+ }
+ else {
+ /* convert "sdddd" to "sdd'dd'" (s = sign, d = digit) */
+ zone_str[7] = 0;
+ zone_str[6] = '\'';
+ zone_str[5] = zone_str[4];
+ zone_str[4] = zone_str[3];
+ zone_str[3] = '\'';
+ }
+ }
+ else if (strcmp(zone_str, "Z") == 0) {
+ /* case "Z", nothing to do */
+ }
+ else if (strcmp(zone_str, "GMT") == 0 ||
+ strcmp(zone_str, "UT") == 0) {
+ /* case Universal Time */
+ zone_str[0] = 'Z';
+ zone_str[1] = 0;
+ }
+ else if (zone_str[1] == 0 &&
+ zone_str[0] >= 'A' &&
+ zone_str[0] <= 'M') {
+ /* Military: A:-1 .. M:-12 */
+ sprintf(zone_str, "-%02d'00'", zone_str[0] - 'A' + 1);
+ }
+ else if (zone_str[1] == 0 &&
+ zone_str[0] >= 'N' &&
+ zone_str[0] <= 'Y') {
+ /* Military: N:+1 .. Y:+12 */
+ sprintf(zone_str, "+%02d'00'", zone_str[0] - 'N' + 1);
+ }
+ else if (strcmp(zone_str, "EDT") == 0) {
+ strcpy(zone_str, "-04'00'");
+ }
+ else if (strcmp(zone_str, "EST") == 0 ||
+ strcmp(zone_str, "CDT") == 0) {
+ strcpy(zone_str, "-05'00'");
+ }
+ else if (strcmp(zone_str, "CST") == 0 ||
+ strcmp(zone_str, "MDT") == 0) {
+ strcpy(zone_str, "-06'00'");
+ }
+ else if (strcmp(zone_str, "MST") == 0 ||
+ strcmp(zone_str, "PDT") == 0) {
+ strcpy(zone_str, "-07'00'");
+ }
+ else if (strcmp(zone_str, "PST") == 0) {
+ strcpy(zone_str, "-08'00'");
+ }
+ else {
+ /* unknown zone format or "%z" is not supported by strftime() */
+ zone_str[0] = 0;
+ }
+
+ /* print result */
+ pdf_printf("/CreationDate (D:%s)\n", time_str);
+ }
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pdftex.ch.diff"
*** pdftex.ch.org Wed Jul 30 20:47:21 2003
--- pdftex.ch Wed Jul 30 20:58:40 2003
***************
*** 4585,4597 ****
pdf_print_ln(")")
@ @<Print the CreationDate key@>=
! pdf_print("/CreationDate (D:");
! pdf_print_int(year);
! pdf_print_two(month);
! pdf_print_two(day);
! pdf_print_two(time div 60);
! pdf_print_two(time mod 60);
! pdf_print_ln("00)")
@ @<Glob...@>=
@!pdftex_banner: str_number; {the complete banner}
--- 4585,4591 ----
pdf_print_ln(")")
@ @<Print the CreationDate key@>=
! print_creation_date;
@ @<Glob...@>=
@!pdftex_banner: str_number; {the complete banner}
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pdftex.defines.diff"
*** pdftex.defines.org Wed Jul 30 20:46:06 2003
--- pdftex.defines Wed Jul 30 21:00:34 2003
***************
*** 50,55 ****
--- 50,56 ----
@define procedure libpdffinish;
@define procedure writestreamlength();
@define procedure printID();
+ @define procedure printcreationdate;
{ functions from vfpacket.c }
@define function newvfpacket();
--X1bOJ3K7DJ5YkBrT--