--- teTeX-1.0/src/texk/web2c/pdfetexdir/pdfetexextra.h.crypt 2001-04-17 06:02:13.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdfetexdir/pdfetexextra.h 2002-11-11 15:59:08.000000000 -0800 @@ -19,10 +19,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define BANNER "This is pdfeTeX, Version 3.14159-0.14h-released-20010417-2.1" +#define BANNER "This is pdfeTeX, Version 3.14159-0.14h-pdfcrypt-20010417-2.1" #define COPYRIGHT_HOLDER \ "The NTS Team (eTeX)/Han The Thanh, Petr Sojka, and Jiri Zlatuska (pdfTeX)" -#define AUTHOR NULL +#define AUTHOR "see (C) above; pdfcrypt by R.S.Carmenes 20010621" #define PROGRAM_HELP PDFETEXHELP #define DUMP_VAR TEXformatdefault #define DUMP_LENGTH_VAR formatdefaultlength --- teTeX-1.0/src/texk/web2c/pdftexdir/epdf.h.crypt 2000-08-21 08:33:02.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/epdf.h 2002-11-11 15:59:08.000000000 -0800 @@ -46,7 +46,7 @@ extern integer get_fontfile(int); extern integer get_fontname(int); extern integer pdfnewobjnum(void); -extern integer read_pdf_info(char*, integer); +extern integer read_pdf_info(char*, char*, integer); extern void embed_whole_font(int); extern void epdf_check_mem(void); extern void epdf_delete(void); @@ -60,10 +60,15 @@ extern void pdfflush(void); extern void pdftex_fail(char *fmt,...); extern void pdftex_warn(char *fmt,...); +extern void tex_printf(char *, ...); extern void write_enc(char **, integer); extern void write_epdf(void); extern void zpdfbegindict(integer); extern void zpdfbeginobj(integer); extern void zpdfcreateobj(integer, integer); extern void zpdfnewdict(integer, integer); + +extern int pdfcrypting; +extern void pdfcrypt_initkey(void); +extern char pdfcrypt_byte(char); } --- teTeX-1.0/src/texk/web2c/pdftexdir/image.h.crypt 2000-08-25 02:31:40.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/image.h 2002-11-11 15:59:08.000000000 -0800 @@ -28,7 +28,6 @@ integer orig_y; integer selected_page; void *doc; - void *xref; } pdf_image_struct; typedef struct { @@ -78,7 +77,7 @@ #define jpg_ptr(N) (img_ptr(N)->image_struct.jpg) #define tif_ptr(N) (img_ptr(N)->image_struct.tif) -extern void read_pdf_info(char*, integer); +extern integer read_pdf_info(char*, char*, integer); extern void write_epdf(void); extern void epdf_delete(void); extern void read_png_info(integer); --- teTeX-1.0/src/texk/web2c/pdftexdir/mapfile.c.crypt 2000-12-19 02:45:17.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/mapfile.c 2002-11-11 15:59:08.000000000 -0800 @@ -14,7 +14,7 @@ fm_entry *fm_cur, *fm_ptr, *fm_tab = 0; static int fm_max; -char *mapfiles; +char *mapfiles = 0; static char nontfm[] = ""; static char *basefont_names[14] = { --- teTeX-1.0/src/texk/web2c/pdftexdir/pdfcrypt.c.crypt 2002-11-11 15:59:08.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdfcrypt.c 2002-11-11 15:59:08.000000000 -0800 @@ -0,0 +1,759 @@ +#include +#include "ptexlib.h" +#include "pdfcrypt.h" + +#undef DebugPW +#ifdef DebugPW +static char pdfcrypt_param_str[84]; +static int pdfcrypt_param_pos = 0; +#endif + +static int pdfcryptstarted = 0; +static int pdfcryptcurrent = 0; + + +static unsigned char ownerKey[64], ownerPassword[64], userKey[64], userPassword[64], fileID[64]; +static int ownerPasswordLength = 0; +static int userPasswordLength = 0; + + +/* previously in gtypes.h */ +typedef unsigned char Guchar; +typedef unsigned long Gulong; + +static Guchar fileKey[16]; +static int fileKeyLen; +static Guchar objKey[21]; +static int objKeyLen; +static Guchar state[256]; +static Guchar x, y; + +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); +static void md5(Guchar *msg, int msgLen, Guchar *digest); + +static Guchar passwordPad[32] = { + 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, + 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, + 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, + 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a +}; + +/*------------------------------------------------------------------------*/ +/* Decrypt */ +/*------------------------------------------------------------------------*/ + + +void pdfcryptpw(strnumber s) +{ + int i, j, a, b; + char *t, ch; + + /* return if no tokens are passed */ + i = strstart[s + 1] - strstart[s]; + if (i <= 0) return; + + t = (char *)gmalloc(64); + + /* Encrypted strings or streams already shipped: ignore \pdfcrypt */ + if (pdfcryptstarted) return; + + /* \pdfcrypt options */ + +#ifdef DebugPW + pdfcrypt_param_pos = 0; + for (i = strstart[s]; i < strstart[s + 1]; i++) pdfcrypt_param_str[pdfcrypt_param_pos++] = strpool[i]; + pdfcrypt_param_str[pdfcrypt_param_pos] = 0; +#endif + + a = 0; + b = 0; + for (i = strstart[s]; i <= strstart[s + 1]; i++) { + if (i == strstart[s + 1]) ch = 32; + else ch = strpool[i]; + + if ( (a == 0) && (ch != 32) ) { a = 1; j = 0; } + else + if ( (a == 1) && ( (ch == 32) || (ch == 61) || (ch == 34) ) ) { + if (strcmp(t, "owner") == 0) { b = 1; ownerPasswordLength = 0; } + else + if (strcmp(t, "user") == 0) { b = 2; userPasswordLength = 0; } + else + if (strcmp(t, "print") == 0) b = 3; + else + if (strcmp(t, "edit") == 0) b = 4; + else + if (strcmp(t, "copy") == 0) b = 5; + else + if (strcmp(t, "annotate") == 0) b = 6; + else + if (strcmp(t, "all") == 0) b = 7; + else + if (strcmp(t, "noprint") == 0) b = 8; + else + if (strcmp(t, "noedit") == 0) b = 9; + else + if (strcmp(t, "nocopy") == 0) b =10; + else + if (strcmp(t, "noannotate") == 0) b =11; + else + if (strcmp(t, "none") == 0) b =12; + else b = 0; + if (b > 2) a = 0; + else a = 2; + } + + if (a == 1) sprintf(t+j++, "%c", ch); + else + if ( (a == 2) && (ch == 34) ) a = 3; + else + if ( (a == 3) && (ch == 34) ) a = 0; + else + if ( (a == 3) || (b > 2) ) + switch (b) { + case 1: ownerPassword[ownerPasswordLength++] = ch; + break; + case 2: userPassword[ userPasswordLength++] = ch; + break; + case 3: pdfcryptpermit |= 0x0004; /* do Print */ + break; + case 4: pdfcryptpermit |= 0x0008; /* do Edit */ + break; + case 5: pdfcryptpermit |= 0x0010; /* do Copy */ + break; + case 6: pdfcryptpermit |= 0x0020; /* do Annotate */ + break; + case 7: pdfcryptpermit |= 0x003c; /* do all */ + break; + case 8: pdfcryptpermit &= 0xfff8; /* no Print */ + break; + case 9: pdfcryptpermit &= 0xfff4; /* no Edit */ + break; + case 10: pdfcryptpermit &= 0xffec; /* no Copy */ + break; + case 11: pdfcryptpermit &= 0xffdc; /* no Annotate */ + break; + case 12: pdfcryptpermit &= 0xffc0; /* none */ + break; + } + } + + ownerPassword[ownerPasswordLength] = 0; + userPassword[ userPasswordLength] = 0; + + gfree(t); +} + + +void pdfcrypt_init() +{ + unsigned char buf[84], key[16], ch; + int i, j, len; + int rev3; + + rev3 = (cfgpar(cfgpdf12compliantcode) == 0 + && cfgpar(cfgpdf13compliantcode) == 0 + && cfgpar(cfgpdf14compliantcode) != 0); + + /* calculate a fileID: trailer << /ID [<16 bytes><16 bytes>] >> */ + srandom(time(NULL)); + for (i = 0; i < 16; i++) { + ch = random() & 0xff; + fileID[i] = ch; + fileID[i+16] = fileID[i]; + sprintf(buf+2*i, "%02x", ch); + } + buf[32] = 0; +#ifdef DebugPW + sprintf(buf,"%s;%s[P%d,E%d,C%d,A%d]", &ownerPassword, \ + &userPassword, \ + (pdfcryptpermit & 0x0004) >> 2, \ + (pdfcryptpermit & 0x0008) >> 3, \ + (pdfcryptpermit & 0x0010) >> 4, \ + (pdfcryptpermit & 0x0020) >> 5); +#endif + pdfcryptid1=maketexstring(buf); +#ifdef DebugPW + sprintf(buf, "%s", &pdfcrypt_param_str); +#endif + pdfcryptid2=maketexstring(buf); + + /* Computing the O(wner) value of the Encryption dictionary */ + + /* Adjust owner password string to 32 bytes as previously (or user pw if none) */ + if (ownerPasswordLength == 0) { + memcpy(ownerPassword, userPassword, 32); + ownerPasswordLength = userPasswordLength; + } + len = ownerPasswordLength; + if (len < 32) memcpy(ownerPassword + len, passwordPad, 32 - len); + ownerPasswordLength = 32; + + /* => MD5 => use 1st 5 bytes as RC4 key */ + md5(ownerPassword, 32, key); + + if (rev3) + for (i = 0; i < 50; ++i) + md5(key, 16, key); + + /* Adjust user password string to 32 bytes as previously */ + len = userPasswordLength; + if (len < 32) memcpy(userPassword + len, passwordPad, 32 - len); + userPasswordLength = 32; + + /* (RC4 key) and (adjusted user pw) => RC4 => store output as O value */ + x = y = 0; + len = rev3 ? cfgpar(cfgcryptkeybits) / 8 : 5; + rc4InitKey(key, len, state); + for (i = 0; i < 32; ++i) + ownerKey[i] = rc4DecryptByte(state, &x, &y, userPassword[i]); + + if (rev3) { + for (j = 1; j <= 19; ++j) { + unsigned char tmpkey[16]; + x = y = 0; + for (i = 0; i < len; ++i) + tmpkey[i] = key[i] ^ (unsigned char) j; + rc4InitKey(tmpkey, len, state); + for (i = 0; i < 32; ++i) + ownerKey[i] = rc4DecryptByte(state, &x, &y, ownerKey[i]); + } + } + + for (i = 0; i < 32; ++i) + sprintf(buf+2*i, "%02x", ownerKey[i]); + buf[64]=0; + pdfcryptovalue=maketexstring(buf); + + + /* Computing the U(ser) value of the Encryption dictionary */ + + /* Create a 5-byte key using the 5-bytes-key generation algorithm from the user pw */ + + /* Adjust user password string to 32 bytes as previously (already done) */ + memcpy(buf, userPassword, 32); + + /* Append 32-byte O(wner) value of the Encryption dictionary */ + memcpy(buf+32, ownerKey, 32); + + /* Append P(ermission) value trated as a 4-byte unsigned number */ + /* memcpy(buf+64, pdfcryptpermit, 4); */ + buf[64] = pdfcryptpermit & 0xff; + buf[65] = (pdfcryptpermit >> 8) & 0xff; + buf[66] = (pdfcryptpermit >> 16) & 0xff; + buf[67] = (pdfcryptpermit >> 24) & 0xff; + + /* Append 1st element of file's file identifier: trailer<<2nd>]>> */ + memcpy(buf+68, fileID, 16); + + /* Finish the hash. */ + md5(buf, 84, key); + + if (rev3) { + /* => take 1st N bytes of output as the key */ + fileKeyLen = cfgpar(cfgcryptkeybits) / 8; + /* Feed the previous result 50 times into MD5. */ + for (i = 0; i < 50; ++i) + md5(key, fileKeyLen, key); + } else { + /* => take 1st 5 bytes of output as the key */ + fileKeyLen = 5; + } + /* => take 1st N bytes of output as the key */ + memcpy(fileKey, key, fileKeyLen); + + if (rev3) { + unsigned char res[16]; + /* step 2: MD5 is padding string */ + memcpy(buf, passwordPad, 32); + /* step 3: pass first element of file ID */ + memcpy(buf+32, fileID, 16); + /* finish MD5 */ + md5(buf, 48, res); + /* encrypt MD5 result */ + x = y = 0; + rc4InitKey(fileKey, fileKeyLen, state); + for (i = 0; i < 16; ++i) + res[i] = rc4DecryptByte(state, &x, &y, res[i]); + for (j = 1; j <= 19; ++j) { + unsigned char tmpkey[16]; + x = y = 0; + for (i = 0; i < fileKeyLen; ++i) + tmpkey[i] = fileKey[i] ^ j; + rc4InitKey(tmpkey, fileKeyLen, state); + for (i = 0; i < 16; ++i) + res[i] = rc4DecryptByte(state, &x, &y, res[i]); + } + for (i = 0; i < 16; ++i) + sprintf(buf+2*i, "%02x", res[i]); + for (i = 16; i < 32; ++i) + sprintf(buf+2*i, "%02x", random () % 256); + } else { + /* (5-byte key) and (32-byte padding string) => RC4 => store output as U value */ + x = y = 0; + rc4InitKey(fileKey, fileKeyLen, state); + for (i = 0; i < 32; ++i) { + ch = rc4DecryptByte(state, &x, &y, passwordPad[i]); + userKey[i] = ch; + sprintf(buf+2*i, "%02x", ch); + } + } + buf[64]=0; + pdfcryptuvalue=maketexstring(buf); +} + + +void pdfcrypt_initkey() +{ + int pdfcryptobjgen = 0; /* in case there is ever an object generation <> 0 */ + + if (!pdfcryptstarted) { + pdfcryptstarted = 1; + pdfcrypt_init(); + } + + if (pdfcryptcurrent != pdfcryptobjnum) { + pdfcryptcurrent = pdfcryptobjnum; + + /* construct object key */ + memcpy(objKey, fileKey, fileKeyLen); + objKeyLen = fileKeyLen; + objKey[objKeyLen++] = pdfcryptobjnum & 0xff; + objKey[objKeyLen++] = (pdfcryptobjnum >> 8) & 0xff; + objKey[objKeyLen++] = (pdfcryptobjnum >> 16) & 0xff; + objKey[objKeyLen++] = pdfcryptobjgen & 0xff; + objKey[objKeyLen++] = (pdfcryptobjgen >> 8) & 0xff; + md5(objKey, objKeyLen, objKey); + if (objKeyLen > 16) + objKeyLen = 16; + } + + /* set up for decryption */ + x = y = 0; + rc4InitKey(objKey, objKeyLen, state); +} + + +char *add_ch(char *t, char *s, int *x, int encrypt) +{ + char ch; + + ch = s[0]; + *x = 1; + if ( (encrypt) && (ch == 92) ) { + switch (s[1]) { + case 40: ch=40; (*x)++; break; /* \( */ + case 41: ch=41; (*x)++; break; /* \) */ + case 92: ch=92; (*x)++; break; /* \\ */ + case 98: ch= 8; (*x)++; break; /* \b */ + case 116: ch= 9; (*x)++; break; /* \t */ + case 110: ch=10; (*x)++; break; /* \n */ + case 102: ch=12; (*x)++; break; /* \f */ + case 114: ch=13; (*x)++; break; /* \r */ + default: /* octal */ + /* HO, 2002-01-09: backslash should not be ignored, if no + special character is followed (b,t,n,r,\,(,),0-8) */ + if ( (s[*x] > 47) && (s[*x] < 56) ) { + ch = s[(*x)++] - 48; + if ( (s[*x] > 47) && (s[*x] < 56) ) ch = s[(*x)++] - 48 + ch*8; + if ( (s[*x] > 47) && (s[*x] < 56) ) ch = s[(*x)++] - 48 + ch*8; + } + else { + /* ignore backslash, if the next character is not special */ + ch = s[(*x)++]; + } + } + } + if (encrypt) ch = pdfcrypt_byte(ch); + switch (ch) { + case 0: +/* + case 8: + case 9: + case 10: + case 12: +*/ + case 13: + case 14: sprintf(t, "\\%03o", ch); t += 4; break; + case 40: + case 41: + case 92: if (encrypt) sprintf(t++, "\\"); + default: sprintf(t++, "%c", ch); + } + return t; +} + +strnumber pdfcrypt_maketexstring(char *s, int l) +{ + if (s == 0 || l == 0) + return getnullstr(); + check_buf(poolptr + l, poolsize); + while (l-- > 0) + strpool[poolptr++] = *s++; + last_tex_string = makestring(); + return last_tex_string; +} + +int pdfcrypt_object(unsigned char **pool, int len) +{ + int encrypt, i, j, k, x, parenlevel, stream; + unsigned char *t, *tstart, *obj, ch, chs; + + if ( (!pdfcrypting) || (len <= 0) ) return len; + obj = *pool; + + parenlevel = 0; + t = tstart = (unsigned char *)gmalloc(len * 4); + for (i = 0; i < len; i += x) { + ch = obj[i]; + stream = 0; + + if ( ch == 40 ) { + if (parenlevel == 0) pdfcrypt_initkey(); + parenlevel++; + } + else + if ( ch == 41 ) { parenlevel--; } + else + if ( (parenlevel == 0) && ( ch == 62 ) && ( obj[i + 1] == 62 ) && (i < len - 15) ) { + /* + Very dirty hack to find streams: a proper parser is needed here. + It will fail if the input contains more than one stream: + for example, with user-defined object arrays. + */ + /* search the begining of a stream */ + j= i + 1; + do { chs = obj[++j]; } + while ( ( j < len - 15) && + ( ( chs == 32 ) || ( chs == 9 ) || ( chs == 10 ) || ( chs == 13 ) ) + ); + if ( ( j < len - 15) && ( strncmp(obj + j, "stream", 6) == 0 )) { + /* stream found, search the end */ + stream = 1; + j += 6; + if ( obj[j] == 13 ) j++; + if ( obj[j] == 10 ) j++; + /* j now stores the pos of the first char in the stream */ + k = len - 9; + while ( (k > j) && ( strncmp(obj + k, "endstream", 9) != 0 ) ) k--; + /* k now stores the pos of the last+1 char in the stream */ + if ( strncmp(obj + k, "endstream", 9) == 0 ) { + /* send chars leading the stream unencrypted */ + for (x = i; x < j; x++) *t++ = obj[x]; + /* send the stream encrypted */ + pdfcrypt_initkey(); + for (x = j; x < k; x++) *t++ = pdfcrypt_byte(obj[x]); + /* send chars closing the stream unencrypted */ + for (x = k; x < k + 9; x++) *t++ = obj[x]; + /* and continue normally */ + i = x; + x = 0; + } + } + } + + if (!stream) { + /* encrypt chars if inside external parenthesis */ + encrypt = !( (!parenlevel) || (parenlevel == 1) && (ch == 40) ); + t = add_ch(t, obj + i, &x, encrypt); + } + } + + len = t - tstart; + *pool = tstart; + return len; +} + + +void pdfcryptfile(bytefile f) +{ + int i, len; + unsigned char *buf, *tstart; + + /* The file is opened and closed in pdftex.ch */ + + /* get the file length to allocate the buffer */ + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + if (len <= 0) return; + + /* allocate the buffer and read the file */ + tstart = buf = (unsigned char *)gmalloc(len); + fread(buf, len, 1, f); + + /* encrypt strings and streams and save the file */ + len = pdfcrypt_object(&tstart, len); + for (i = 0; i < len; i++) pdfout(tstart[i]); + + /* deallocate buffers */ + if (tstart != buf) gfree(tstart); + gfree(buf); +} + + +strnumber pdfcryptstringlist(strnumber s) +{ + int len; + unsigned char *tstart; + + len = strstart[s + 1] - strstart[s]; + if ( (!pdfcrypting) || (len <= 0) ) return s; + tstart = strpool + strstart[s]; + len = pdfcrypt_object(&tstart, len); + + /* do not use maketexstring with encrypted streams: + they may contain NULL chars and they would be truncated */ + s = pdfcrypt_maketexstring(tstart, len); + + if (tstart != strpool) gfree(tstart); + return s; +} + +strnumber pdfcryptstring(strnumber s) +{ + int len, i, x; + char *t, *tstart; + + len = strstart[s + 1] - strstart[s]; + if ( (!pdfcrypting) || (len <= 0) ) return s; + + /* Initialize key for current string */ + pdfcrypt_initkey(); + + t = tstart = (char *)gmalloc(len * 4); + for (i = strstart[s]; i < strstart[s + 1]; i += x) + t = add_ch(t, strpool + i, &x, 1); + + /* ensure that the encrypted string ends with a NULL char */ + *t = 0; + s = maketexstring(tstart); + + gfree(tstart); + return s; +} + +void pdfcryptstream(strnumber s) +{ + int i, len; + + len = strstart[s + 1] - strstart[s]; + if ( (!pdfcrypting) || (len <= 0) ) return; + + /* Initialize key for current stream */ + pdfcrypt_initkey(); + + for (i = strstart[s]; i < strstart[s + 1]; i++) + strpool[i] = pdfcrypt_byte(strpool[i]); +} + + +unsigned char pdfcrypt_byte(unsigned char c) +{ + return rc4DecryptByte(state, &x, &y, c); +} + + +/*------------------------------------------------------------------------*/ +/* RC4-compatible decryption */ +/*------------------------------------------------------------------------*/ + +static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { + Guchar index1, index2; + Guchar t; + int i; + + for (i = 0; i < 256; ++i) + state[i] = i; + index1 = index2 = 0; + for (i = 0; i < 256; ++i) { + index2 = (key[index1] + state[i] + index2) % 256; + t = state[i]; + state[i] = state[index2]; + state[index2] = t; + index1 = (index1 + 1) % keyLen; + } +} + +static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { + Guchar x1, y1, tx, ty; + + x1 = *x = (*x + 1) % 256; + y1 = *y = (state[*x] + *y) % 256; + tx = state[x1]; + ty = state[y1]; + state[x1] = ty; + state[y1] = tx; + return c ^ state[(tx + ty) % 256]; +} + +/*------------------------------------------------------------------------*/ +/* MD5 message digest */ +/*------------------------------------------------------------------------*/ + +static inline Gulong rotateLeft(Gulong x, int r) { + x &= 0xffffffff; + return ((x << r) | (x >> (32 - r))) & 0xffffffff; +} + +static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s); +} + +static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s); +} + +static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s); +} + +static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d, + Gulong Xk, Gulong s, Gulong Ti) { + return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s); +} + +static void md5(Guchar *msg, int msgLen, Guchar *digest) { + Gulong x[16]; + Gulong a, b, c, d, aa, bb, cc, dd; + int n64; + int i, j, k; + + /* compute number of 64-byte blocks */ + /* (length + pad byte (0x80) + 8 bytes for length) */ + n64 = (msgLen + 1 + 8 + 63) / 64; + + /* initialize a, b, c, d */ + a = 0x67452301; + b = 0xefcdab89; + c = 0x98badcfe; + d = 0x10325476; + + /* loop through blocks */ + k = 0; + for (i = 0; i < n64; ++i) { + + /* grab a 64-byte block */ + for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4) + x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k]; + if (i == n64 - 1) { + if (k == msgLen - 3) + x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k]; + else if (k == msgLen - 2) + x[j] = 0x800000 + (msg[k+1] << 8) + msg[k]; + else if (k == msgLen - 1) + x[j] = 0x8000 + msg[k]; + else + x[j] = 0x80; + ++j; + while (j < 16) + x[j++] = 0; + x[14] = msgLen << 3; + } + + /* save a, b, c, d */ + aa = a; + bb = b; + cc = c; + dd = d; + + /* round 1 */ + a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478); + d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756); + c = md5Round1(c, d, a, b, x[2], 17, 0x242070db); + b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee); + a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf); + d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a); + c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613); + b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501); + a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8); + d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af); + c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1); + b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be); + a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122); + d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193); + c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e); + b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821); + + /* round 2 */ + a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562); + d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340); + c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51); + b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa); + a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d); + d = md5Round2(d, a, b, c, x[10], 9, 0x02441453); + c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681); + b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8); + a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6); + d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6); + c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87); + b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed); + a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905); + d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8); + c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9); + b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a); + + /* round 3 */ + a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942); + d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681); + c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122); + b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c); + a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44); + d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9); + c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60); + b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70); + a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6); + d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa); + c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085); + b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05); + a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039); + d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5); + c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8); + b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665); + + /* round 4 */ + a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244); + d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97); + c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7); + b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039); + a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3); + d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92); + c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d); + b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1); + a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f); + d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0); + c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314); + b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1); + a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82); + d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235); + c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb); + b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391); + + /* increment a, b, c, d */ + a += aa; + b += bb; + c += cc; + d += dd; + } + + /* break digest into bytes */ + digest[0] = a & 0xff; + digest[1] = (a >>= 8) & 0xff; + digest[2] = (a >>= 8) & 0xff; + digest[3] = (a >>= 8) & 0xff; + digest[4] = b & 0xff; + digest[5] = (b >>= 8) & 0xff; + digest[6] = (b >>= 8) & 0xff; + digest[7] = (b >>= 8) & 0xff; + digest[8] = c & 0xff; + digest[9] = (c >>= 8) & 0xff; + digest[10] = (c >>= 8) & 0xff; + digest[11] = (c >>= 8) & 0xff; + digest[12] = d & 0xff; + digest[13] = (d >>= 8) & 0xff; + digest[14] = (d >>= 8) & 0xff; + digest[15] = (d >>= 8) & 0xff; +} --- teTeX-1.0/src/texk/web2c/pdftexdir/pdfcrypt.h.crypt 2002-11-11 15:59:08.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdfcrypt.h 2002-11-11 15:59:08.000000000 -0800 @@ -0,0 +1,27 @@ +#ifndef PDFCRYPT_H +#define PDFCRYPT_H + + +/* Initiate encryption passwords */ +void pdfcryptpw(strnumber s); + +/* Initiate stream encryption keys */ +void pdfcrypt_initkey(); + +/* encrypt one byte */ +unsigned char pdfcrypt_byte(unsigned char c); + +/* encrypt one ordinary stream in situ */ +void pdfcryptstream(strnumber s); + +/* encrypt one ordinary string */ +strnumber pdfcryptstring(strnumber s); + +/* encrypt strings that come with pdf code */ +strnumber pdfcryptstringlist(strnumber s); + +/* encrypt object files that come with pdf code */ +void pdfcryptfile(bytefile f); + + +#endif --- teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.ch.crypt 2001-04-17 06:02:13.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.ch 2002-11-11 15:59:08.000000000 -0800 @@ -32,7 +32,7 @@ {printed when \pdfTeX\ starts} @d pdftex_version==14 { \.{\\pdftexversion} } @d pdftex_revision=="h" { \.{\\pdftexrevision} } -@d pdftex_version_string=='14h-released-20010417' {current pdf\TeX\ version} +@d pdftex_version_string=='14h-pdfcrypt-20010417' {current pdf\TeX\ version} @z @@ -610,6 +610,9 @@ cfg_dest_margin_code = pdf_dest_margin_code; cfg_thread_margin_code = pdf_thread_margin_code; cfg_pdf12_compliant_code = pdf_thread_margin_code + 1; +cfg_pdf13_compliant_code = cfg_pdf12_compliant_code + 1; +cfg_pdf14_compliant_code = cfg_pdf13_compliant_code + 1; +cfg_crypt_key_bits = cfg_pdf14_compliant_code + 1; @ Integer parameters are initialized immediately after the config file is read, but dimension parameters are set when opening the PDF output file. @@ -991,6 +994,7 @@ @!pdf_gone: integer; {number of bytes that were flushed to output} @!pdf_save_offset: integer; {to save |pdf_offset|} @!zip_write_state: integer; {which state of compression we are in} +@!pdfcrypting: boolean; {flag to control pdf encryption} @ @= pdf_buf[0] := "%"; @@ -1005,6 +1009,7 @@ pdf_ptr := 9; pdf_gone := 0; zip_write_state := no_zip; +pdfcrypting := false; @ @p function fix_int(val, min, max: integer): integer; @@ -1029,12 +1034,19 @@ output_file_name := b_make_name_string(pdf_file); if cfg_par(cfg_pdf12_compliant_code) > 0 then pdf_buf[7] := "2"; + if cfg_par(cfg_pdf14_compliant_code) > 0 then + pdf_buf[7] := "4"; end; @ The PDF buffer is flushed by calling |pdf_flush|, which checks the -variable |zip_write_state| and will compress the buffer before flushing if +variable |zip_write_state| and will compress and/or encrypt the buffer before flushing if neccesary. We call |pdf_begin_stream| to begin a stream and |pdf_end_stream| to finish it. The stream contents will be compressed if compression is turn on. +write_pdf is no longer used to output streams because they may need encryption; +instead, streams are always sent to write_zip in writezip.c to allow encryption; +write_zip will compress streams if necessary and send them to xfwrite in utils.c; +zip_write_state now flags if pdf_flush has to deal with a stream or not; +ideally, zip_write_state should be renamed to something like stream_write_state. @p procedure pdf_flush; {flush out the |pdf_buf|} begin @@ -1060,26 +1072,16 @@ pdf_print_ln("/Length "); pdf_stream_length_offset := pdf_offset - 11; pdf_stream_length := 0; - if pdf_compress_level > 0 then begin - pdf_print_ln("/Filter /FlateDecode"); - pdf_print_ln(">>"); - pdf_print_ln("stream"); - pdf_flush; - zip_write_state := zip_writting; - end - else begin - pdf_print_ln(">>"); - pdf_print_ln("stream"); - pdf_save_offset := pdf_offset; - end; + if pdf_compress_level > 0 then pdf_print_ln("/Filter /FlateDecode"); + pdf_print_ln(">>"); + pdf_print_ln("stream"); + pdf_flush; + zip_write_state := zip_writting; end; procedure pdf_end_stream; {end a stream} begin - if pdf_compress_level > 0 then - zip_write_state := zip_finish - else - pdf_stream_length := pdf_offset - pdf_save_offset; + zip_write_state := zip_finish; pdf_flush; write_stream_length(pdf_stream_length, pdf_stream_length_offset); pdf_print_ln("endstream"); @@ -1843,7 +1845,9 @@ @= @!inf_obj_tab_size = 32000; {min size of the cross-reference table for PDF output} -@!sup_obj_tab_size = 524288; {max size of the cross-reference table for PDF output} +@!sup_obj_tab_size = 8388607; {max size of the cross-reference table for PDF output} +@!inf_dest_names_size = 10000; {min size of the destination names table for PDF output} +@!sup_dest_names_size = 131072; {max size of the destination names table for PDF output} @ @= @!obj_tab_size:integer; @@ -1857,8 +1861,10 @@ @!pdf_stream_length_offset: integer; {file offset of the last stream length} @!pdf_append_list_arg: integer; {for use with |pdf_append_list|} @!ff: integer; {for use with |set_ff|} +@!pdfcrypt_objnum: integer; {current object number} @ @= +pdfcrypt_objnum := 0; obj_ptr := 0; for k := 1 to head_tab_max do head_tab[k] := 0; @@ -1879,8 +1885,8 @@ @= procedure append_dest_name(s: str_number; n: integer); begin - if pdf_dest_names_ptr = max_dest_names then - overflow("number of destination names", max_dest_names); + if pdf_dest_names_ptr = dest_names_size then + overflow("number of destination names", dest_names_size); dest_names[pdf_dest_names_ptr].objname := s; dest_names[pdf_dest_names_ptr].objnum := n; incr(pdf_dest_names_ptr); @@ -1936,6 +1942,7 @@ obj_offset(i) := pdf_offset; pdf_print_int(i); pdf_print_ln(" 0 obj"); + pdfcrypt_objnum := i; end; procedure pdf_end_obj; @@ -1948,6 +1955,7 @@ obj_offset(i) := pdf_offset; pdf_print_int(i); pdf_print_ln(" 0 obj <<"); + pdfcrypt_objnum := i; end; procedure pdf_end_dict; {end a PDF object of type dictionary} @@ -2052,10 +2060,13 @@ procedure pdf_print_str(s: str_number); {print out |s| as string in PDF output} +var t: str_number; begin + t := pdfcrypt_string(s); pdf_out("("); - pdf_print(s); + pdf_print(t); pdf_out(")"); + if t<>s then flush_str(t); end; procedure pdf_print_str_ln(s: str_number); {print out |s| as string in PDF @@ -3004,25 +3015,39 @@ end; procedure pdf_print_toks(p: pointer); {print tokens list |p|} -var s: str_number; +var s,t: str_number; begin s := tokens_to_string(p); - if length(s) > 0 then - pdf_print(s); + if length(s) > 0 then begin + t := pdfcrypt_string_list(s); + pdf_print(t); + if t<>s then flush_str(t); + end; flush_str(s); end; procedure pdf_print_toks_ln(p: pointer); {print tokens list |p|} -var s: str_number; +var s,t: str_number; begin s := tokens_to_string(p); if length(s) > 0 then begin - pdf_print(s); + t := pdfcrypt_string_list(s); + pdf_print(t); pdf_print_nl; + if t<>s then flush_str(t); end; flush_str(s); end; +procedure pdfcrypt_get_toks(p: pointer); {get tokens list |p|} +var s: str_number; +begin + pdfcrypting := true; + s := tokens_to_string(p); + pdfcrypt_pw(s); + flush_str(s); +end; + @ Similiar to |vlist_out|, |pdf_vlist_out| needs to be declared forward @p procedure@?pdf_vlist_out; forward; @@ -3673,7 +3698,7 @@ @ @= procedure pdf_write_obj(n: integer); {write a raw PDF object} -var s: str_number; +var s,t: str_number; f: byte_file; begin s := tokens_to_string(obj_obj_data(n)); @@ -3697,6 +3722,9 @@ pdf_error("ext5", "cannot open file for embedding"); print("<<"); print(s); + if pdfcrypting then + pdfcrypt_file(f) + else while not eof(f) do pdf_out(getc(f)); print(">>"); @@ -3704,8 +3732,11 @@ end else if obj_obj_is_stream(n) > 0 then pdf_print(s) - else - pdf_print_ln(s); + else begin + t := pdfcrypt_string_list(s); + pdf_print_ln(t); + if t<>s then flush_str(t); + end; if obj_obj_is_stream(n) > 0 then pdf_end_stream else @@ -4047,7 +4078,7 @@ fixed_pk_resolution := fix_int(pdf_pk_resolution, 72, 2400); pk_scale_factor := divide_scaled(72, fixed_pk_resolution, 5 + fixed_decimal_digits); -set_job_id(year, month, day, time); +set_job_id(year, month, day, time, pdftex_version, pdftex_revision); if (pdf_unique_resname > 0) and (pdf_resname_prefix = 0) then pdf_resname_prefix := get_resname_prefix @@ -4124,6 +4155,7 @@ @; @; @; + @; @; @; pdf_flush; @@ -4410,31 +4442,60 @@ @ @= pdf_new_dict(obj_type_others, 0); -@; +pdf_str_entry_ln("Producer", pdfcrypt_version); if pdf_info_toks <> null then begin pdf_print_toks_ln(pdf_info_toks); delete_toks(pdf_info_toks); end; -pdf_str_entry_ln("Creator", "TeX"); -@; +pdf_str_entry_ln("CreationDate", pdfcrypt_date); pdf_end_dict -@ @= -pdf_print("/Producer (pdfTeX-"); -pdf_print_int(pdftex_version div 100); -pdf_out("."); -pdf_print_int(pdftex_version mod 100); -pdf_print(pdftex_revision); -pdf_print_ln(")") - -@ @= -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)") +@ @= +if pdfcrypting then begin + pdf_new_dict(obj_type_others, 0); + pdf_print_ln("/Filter /Standard"); + if (cfg_par(cfg_pdf12_compliant_code) = 0) and (cfg_par(cfg_pdf13_compliant_code) = 0) and (cfg_par(cfg_pdf14_compliant_code) <> 0) then begin + pdf_print_ln("/V 2"); + pdf_print_ln("/R 3"); + pdf_print("/Length "); + pdf_print_int(cfg_par(cfg_crypt_key_bits)); + pdf_print_ln(""); + end + else begin + pdf_print_ln("/V 1"); + pdf_print_ln("/R 2"); + end; + @; + @; + @; + pdf_end_dict; +end + +@ @= +@!pdfcrypt_version: str_number;{/Producer} +@!pdfcrypt_date: str_number; {/CreationDate} +@!pdfcrypt_id1: str_number; {1st psrt of file id} +@!pdfcrypt_id2: str_number; {2nd psrt of file id} +@!pdfcrypt_ovalue: str_number; {owner value} +@!pdfcrypt_uvalue: str_number; {user value} +@!pdfcrypt_permit: integer; {user permissions} + +@ @= +pdfcrypt_permit := 65532; + +@ @= +pdf_print("/O <"); +pdf_print(pdfcrypt_ovalue); +pdf_print_ln(">"); + +@ @= +pdf_print("/U <"); +pdf_print(pdfcrypt_uvalue); +pdf_print_ln(">"); + +@ @= +pdf_print("/P "); +pdf_print_int_ln(pdfcrypt_permit); @ @= l := 0; @@ -4465,7 +4526,19 @@ pdf_print_ln("<<"); pdf_int_entry_ln("Size", obj_ptr + 1); pdf_indirect_ln("Root", root); -pdf_indirect_ln("Info", obj_ptr); +if not pdfcrypting + then begin + pdf_indirect_ln("Info", obj_ptr); + end + else begin + pdf_indirect_ln("Info", obj_ptr - 1); + pdf_indirect_ln("Encrypt", obj_ptr); + pdf_print("/ID [<"); + pdf_print(pdfcrypt_id1); + pdf_print("><"); + pdf_print(pdfcrypt_id2); + pdf_print_ln(">]"); + end; pdf_print_ln(">>"); pdf_print_ln("startxref"); pdf_print_int_ln(pdf_save_offset); @@ -6012,6 +6085,37 @@ end; @z + ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++% Output statistics about the pdftex specific sizes. ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x [1334] + wlog_ln(' ',max_in_stack:1,'i,',max_nest_stack:1,'n,',@| + max_param_stack:1,'p,',@| + max_buf_stack+1:1,'b,',@| + max_save_stack+6:1,'s stack positions out of ',@| + stack_size:1,'i,', + nest_size:1,'n,', + param_size:1,'p,', + buf_size:1,'b,', + save_size:1,'s'); + end +@y + wlog_ln(' ',max_in_stack:1,'i,',max_nest_stack:1,'n,',@| + max_param_stack:1,'p,',@| + max_buf_stack+1:1,'b,',@| + max_save_stack+6:1,'s stack positions out of ',@| + stack_size:1,'i,', + nest_size:1,'n,', + param_size:1,'p,', + buf_size:1,'b,', + save_size:1,'s'); + wlog_ln(' ',obj_ptr:1,' PDF objects out of ',obj_tab_size:1); + wlog_ln(' ',pdf_dest_names_ptr:1,' named destinations out of ',dest_names_size:1); + wlog_ln(' ',pdf_mem_ptr:1,' words of extra memory for PDF output out of ',pdf_mem_size:1); + end +@z + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Read config file before input %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -6064,6 +6168,7 @@ @d pdf_include_chars_code == 31 @d pdf_font_expand_code == 32 @d pdf_map_file_code == 33 +@d pdfcrypt_code == 34 @z @x [1344] @@ -6128,6 +6233,8 @@ @!@:pdf_font_expand_}{\.{\\pdffontexpand} primitive@> primitive("pdfmapfile",extension,pdf_map_file_code);@/ @!@:pdf_map_file_}{\.{\\pdfmapfile} primitive@> +primitive("pdfcrypt",extension,pdfcrypt_code);@/ +@!@:pdfcrypt_}{\.{\\pdfcrypt} primitive@> @z @x [1346] @@ -6163,6 +6270,7 @@ pdf_font_attr_code: print_esc("pdffontattr"); pdf_font_expand_code: print_esc("pdffontexpand"); pdf_map_file_code: print_esc("pdfmapfile"); + pdfcrypt_code: print_esc("pdfcrypt"); othercases print("[unknown extension!]") @z @@ -6199,6 +6307,7 @@ pdf_font_attr_code: @; pdf_font_expand_code: @; pdf_map_file_code: @; +pdfcrypt_code: @; othercases confusion("ext1") @z @@ -6242,6 +6351,8 @@ @ We have to check whether \.{\\pdfoutput} is set for using \pdfTeX{} extensions. +@d scan_pdf_ext_toks == call_func(scan_toks(false, true)); {like \.{\\special}} + @= procedure check_pdfoutput(s: str_number); begin @@ -6261,7 +6372,7 @@ pdf_literal_direct(tail) := 1 else pdf_literal_direct(tail) := 0; - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; pdf_literal_data(tail) := def_ref; end @@ -6285,7 +6396,7 @@ if scan_keyword("stream") then begin obj_obj_is_stream(k) := 1; if scan_keyword("attr") then begin - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; obj_obj_stream_attr(k) := def_ref; end else @@ -6297,7 +6408,7 @@ obj_obj_is_file(k) := 1 else obj_obj_is_file(k) := 0; - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; obj_obj_data(k) := def_ref; pdf_last_obj := k; end @@ -6338,13 +6449,13 @@ k := obj_ptr; obj_data_ptr(k) := pdf_get_mem(pdfmem_xform_size); if scan_keyword("attr") then begin - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; obj_xform_attr(k) := def_ref; end else obj_xform_attr(k) := null; if scan_keyword("resources") then begin - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; obj_xform_resources(k) := def_ref; end else @@ -6501,6 +6612,7 @@ label reswitch; var p: pointer; k: integer; + named: str_number; s: str_number; page: integer; begin @@ -6513,21 +6625,28 @@ obj_ximage_height(k) := height(alt_rule); obj_ximage_depth(k) := depth(alt_rule); if scan_keyword("attr") then begin - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; obj_ximage_attr(k) := def_ref; end else obj_ximage_attr(k) := null; - if scan_keyword("page") then begin + named := 0; + if scan_keyword("named") then begin + scan_pdf_ext_toks; + named := tokens_to_string(def_ref); + delete_token_ref(def_ref); + end + else if scan_keyword("page") then begin scan_int; page := cur_val; end else page := 1; - call_func(scan_toks(false, true)); {like \.{\\special}} + scan_pdf_ext_toks; s := tokens_to_string(def_ref); delete_token_ref(def_ref); - obj_ximage_data(k) := read_image(s, page); + obj_ximage_data(k) := read_image(s, page, named); + if named <> 0 then flush_str(named); flush_str(s); scale_image(k); pdf_last_ximage := k; @@ -7099,6 +7218,18 @@ pdf_names_toks := concat_tokens(pdf_names_toks, def_ref); end +@ @= +begin + check_pdfoutput("\pdfcrypt"); + call_func(scan_toks(false, true)); + pdfcrypt_toks := concat_tokens(pdfcrypt_toks, def_ref); + if pdfcrypt_toks <> null then begin + if pdfcrypt_objnum = 0 then + pdfcrypt_get_toks(pdfcrypt_toks); + delete_toks(pdfcrypt_toks); + end; +end + @ The following subroutines are about PDF-specific font issues. @= @@ -7681,9 +7812,6 @@ @ Shiping out PDF mark. -@= -@!max_dest_names=20000; {maximum number of names in name tree of PDF -output file} @ @= dest_name_entry = record @@ -7726,9 +7854,11 @@ @!pdf_catalog_openaction: integer; @!pdf_names_toks: pointer; {additional keys of Names dictionary} @!pdf_dest_names_ptr: integer; {first unused position in |dest_names|} -@!dest_names: array[0..max_dest_names] of dest_name_entry; +@!dest_names_size: integer; {maximum number of names in name tree of PDF output file} +@!dest_names: ^dest_name_entry; @!image_orig_x, image_orig_y: integer; {origin of cropped pdf images} @!link_level_stack: pointer; {stack to save |pdf_link_level|} +@!pdfcrypt_toks: pointer; {pdfcrypt token options} @ @= pdf_link_level := -1; @@ -7744,6 +7874,7 @@ pdf_catalog_toks := null; pdf_names_toks := null; pdf_catalog_openaction := 0; +pdfcrypt_toks := null; @ The following procedures are needed for outputing whatsit nodes for pdfTeX. @@ -7765,9 +7896,7 @@ (str_pool[str_start[s] + length(s) - 1] = 41) then pdf_print(s) else begin - pdf_out("("); - pdf_print(s); - pdf_out(")"); + pdf_print_str(s); end; flush_str(s); pdf_print(" "); --- teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.defines.crypt 2000-07-31 13:01:09.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.defines 2002-11-11 15:59:08.000000000 -0800 @@ -62,4 +62,11 @@ { functions from writezip.c } @define procedure writezip(); +{ functions from pdfcrypt.c } +@define procedure pdfcryptpw(); +@define procedure pdfcryptstream(); +@define procedure pdfcryptfile(); +@define function pdfcryptstring(); +@define function pdfcryptstringlist(); + { end of pdftex.defines } --- teTeX-1.0/src/texk/web2c/pdftexdir/pdftexextra.h.crypt 2001-04-17 06:02:13.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdftexextra.h 2002-11-11 15:59:08.000000000 -0800 @@ -19,9 +19,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define BANNER "This is pdfTeX, Version 3.14159-0.14h-released-20010417" +#define BANNER "This is pdfTeX, Version 3.14159-0.14h-pdfcrypt-20010417" #define COPYRIGHT_HOLDER "Han The Thanh, Petr Sojka, and Jiri Zlatuska" -#define AUTHOR NULL +#define AUTHOR "see (C) above; pdfcrypt by R.S.Carmenes 20010621" #define PROGRAM_HELP PDFTEXHELP #define DUMP_VAR TEXformatdefault #define DUMP_LENGTH_VAR formatdefaultlength --- teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.version.crypt 2001-04-17 06:02:13.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdftex.version 2002-11-11 15:59:08.000000000 -0800 @@ -1 +1 @@ -0.14h-released-20010417 +0.14h-pdfcrypt-20010417 --- teTeX-1.0/src/texk/web2c/pdftexdir/pdftoepdf.cc.crypt 2001-03-10 01:02:02.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/pdftoepdf.cc 2002-11-11 15:59:08.000000000 -0800 @@ -21,7 +21,24 @@ #include "epdf.h" -#define obj_free(obj) if (!obj.isNull()) obj.free() +// PdfObject encapsulates the xpdf Object type, and properly +// frees its resources on destruction. +// Use obj-> to access members of the Object, and +// &obj to get a pointer to the object. +// It is no longer necessary to call Object::free explicitely. + +class PdfObject { +public: + PdfObject() { /* nothing */ } + ~PdfObject() { iObject.free(); } + Object* operator->() { return &iObject; } + Object* operator&() { return &iObject; } +private: // no copying or assigning + PdfObject(const PdfObject &); + void operator=(const PdfObject &); +public: + Object iObject; +}; // when copying the Resources of the selected page, all objects are copied // recusively top-down. Indirect objects however are not fetched during @@ -41,7 +58,8 @@ InObj *next; // next entry in list of indirect objects integer num; // new object number in output PDF int fontmap; // index of font map entry - integer encoding; // Encoding for objFont + integer encoding; // Encoding for objFont + int written; // has it been written to output PDF? }; struct UsedEncoding { @@ -50,14 +68,79 @@ UsedEncoding *next; }; -InObj *inObjList; -UsedEncoding *encodingList; +static InObj *inObjList; +static UsedEncoding *encodingList; static GBool isInit = gFalse; +// -------------------------------------------------------------------- +// Maintain list of open embedded PDF files +// -------------------------------------------------------------------- + +struct PdfDocument { + char *file_name; + PDFDoc *doc; + XRef *xref; + InObj *inObjList; + PdfDocument *next; +}; + +static PdfDocument *pdfDocuments = 0; + +// Returns pointer to PdfDocument record for PDF file. +// Creates a new record if it doesn't exist yet. +// xref is made current for the document. + +static PdfDocument *find_add_document(char *file_name) +{ + PdfDocument *p = pdfDocuments; + while (p && strcmp(p->file_name, file_name) != 0) + p = p->next; + if (p) { + xref = p->xref; + return p; + } + p = new PdfDocument; + p->file_name = strdup(file_name); + p->xref = xref = 0; + GString *docName = new GString(p->file_name); + p->doc = new PDFDoc(docName); // takes ownership of docName + if (!p->doc->isOk() || !p->doc->okToPrint()) + pdftex_fail("xpdf: reading PDF image failed"); + p->inObjList = 0; + p->next = pdfDocuments; + pdfDocuments = p; + return p; +} + +// Deallocate a PdfDocument with all its resources +static void delete_document(PdfDocument *pdf_doc) +{ + PdfDocument **p = &pdfDocuments; + while (*p && *p != pdf_doc) + p = &((*p)->next); + // should not happen: + if (!*p) + return; + // unlink from list + *p = pdf_doc->next; + // free pdf_doc's resources + InObj *r, *n; + for (r = pdf_doc->inObjList; r != 0; r = n) { + n = r->next; + delete r; + } + xref = pdf_doc->xref; + delete pdf_doc->doc; + xfree(pdf_doc->file_name); + delete pdf_doc; +} + +// -------------------------------------------------------------------- + static int addEncoding(GfxFont *gfont) { UsedEncoding *n; - n = new UsedEncoding[1]; + n = new UsedEncoding; n->next = encodingList; encodingList = n; n->font = gfont; @@ -76,7 +159,7 @@ static int addInObj(InObjType type, Ref ref, int f, integer e) { - InObj *p, *q, *n = new InObj[1]; + InObj *p, *q, *n = new InObj; if (ref.num == 0) pdftex_fail("pdf inclusion: invalid reference"); n->ref = ref; @@ -84,6 +167,7 @@ n->next = 0; n->fontmap = f; n->encoding = e; + n->written = 0; if (inObjList == 0) inObjList = n; else { @@ -94,6 +178,9 @@ } q = p; } + // it is important to add new objects at the end of the list, + // because new objects are being added while the list is being + // written out. q->next = n; } n->num = pdfnewobjnum(); @@ -106,7 +193,8 @@ { pdf_puts("/"); for (; *s != 0; s++) { - if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_') + if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' || + *s == '.' || *s == '-' ) pdfout(*s); else pdf_printf("#%.2X", *s & 0xFF); @@ -115,12 +203,11 @@ static void copyDictEntry(Object *obj, int i) { - Object obj1; + PdfObject obj1; copyName(obj->dictGetKey(i)); pdf_puts(" "); obj->dictGetValNF(i, &obj1); copyObject(&obj1); - obj1.free(); pdf_puts("\n"); } @@ -175,91 +262,90 @@ { int c; str->reset(); + if (pdfcrypting) pdfcrypt_initkey(); while ((c = str->getChar()) != EOF) - pdfout(c); + if (pdfcrypting) pdfout(pdfcrypt_byte(c)); + else pdfout(c); } static void copyProcSet(Object *obj) { int i, l; - Object procset; + PdfObject procset; if (!obj->isArray()) pdftex_fail("pdf inclusion: invalid ProcSet array type <%s>", obj->getTypeName()); pdf_puts("/ProcSet [ "); for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { obj->arrayGet(i, &procset); - if (!procset.isName()) + if (!procset->isName()) pdftex_fail("pdf inclusion: invalid ProcSet entry type <%s>", - procset.getTypeName()); - copyName(procset.getName()); + procset->getTypeName()); + copyName(procset->getName()); pdf_puts(" "); - procset.free(); } pdf_puts("]\n"); } static void copyFont(char *tag, Object *fontRef) { - Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset; + PdfObject fontdict, subtype, basefont, fontdescRef, fontdesc, charset; GfxFont *gfont; int fontmap; - fontdict.initNull(); - subtype.initNull(); - basefont.initNull(); - fontdescRef.initNull(); - fontdesc.initNull(); + // Check whether the font has already been embedded before analysing it. + InObj *p; + Ref ref = fontRef->getRef(); + for (p = inObjList; p; p = p->next) { + if (p->ref.num == ref.num && p->ref.gen == ref.gen) { + copyName(tag); + pdf_printf(" %d 0 R ", p->num); + return; + } + } fontRef->fetch(&fontdict); - if (!fontdict.isDict()) + if (!fontdict->isDict()) pdftex_fail("pdf inclusion: invalid font dict type <%s>", - fontdict.getTypeName()); - fontdict.dictLookup("Subtype", &subtype); - if (!subtype.isName()) + fontdict->getTypeName()); + fontdict->dictLookup("Subtype", &subtype); + if (!subtype->isName()) pdftex_fail("pdf inclusion: invalid font Subtype entry type <%s>", - subtype.getTypeName()); + subtype->getTypeName()); /* only handle Type1 fonts; others will be copied */ - if (strcmp(subtype.getName(), "Type1") != 0 ) { - copyName(tag); - pdf_puts(" "); - copyObject(fontRef); - goto free_objects; + if (strcmp(subtype->getName(), "Type1") != 0 ) { + copyName(tag); + pdf_puts(" "); + copyObject(fontRef); + return; } - fontdict.dictLookup("BaseFont", &basefont); - if (!basefont.isName()) + fontdict->dictLookup("BaseFont", &basefont); + if (!basefont->isName()) pdftex_fail("pdf inclusion: invalid font BaseFont entry type <%s>", - basefont.getTypeName()); - fontmap = lookup_fontmap(basefont.getName()); + basefont->getTypeName()); + fontmap = lookup_fontmap(basefont->getName()); if (fontmap >= 0 && is_type1(fontmap) && - fontdict.dictLookupNF("FontDescriptor", &fontdescRef) && - fontdescRef.isRef() && fontdescRef.fetch(&fontdesc)) { - if (fontdesc.dictLookup("CharSet", &charset) && - charset.isString() && is_subsetable(fontmap)) { - mark_glyphs(fontmap, charset.getString()->getCString()); - charset.free(); - } + fontdict->dictLookupNF("FontDescriptor", &fontdescRef) && + fontdescRef->isRef() && fontdescRef->fetch(&fontdesc) && + fontdesc->isDict()) { + if (fontdesc->dictLookup("CharSet", &charset) && + charset->isString() && is_subsetable(fontmap)) + mark_glyphs(fontmap, charset->getString()->getCString()); else embed_whole_font(fontmap); - addFontDesc(fontdescRef.getRef(), fontmap); + addFontDesc(fontdescRef->getRef(), fontmap); } copyName(tag); - if (!fontdesc.isNull()) { - gfont = new GfxFont(tag, fontRef->getRef(), fontdict.getDict()); + if (fontdesc->isDict()) { + gfont = new GfxFont(tag, fontRef->getRef(), fontdict->getDict()); pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fontmap, addEncoding(gfont))); } else pdf_printf(" %d 0 R ", addOther(fontRef->getRef())); -free_objects: - obj_free(fontdict); - obj_free(subtype); - obj_free(basefont); - obj_free(fontdescRef); - obj_free(fontdesc); } static void copyFontResources(Object *obj) { - Object fontRef; + PdfObject fontRef; int i, l; if (!obj->isDict()) pdftex_fail("pdf inclusion: invalid font resources dict type <%s>", @@ -267,19 +353,18 @@ pdf_puts("/Font << "); for (i = 0, l = obj->dictGetLength(); i < l; ++i) { obj->dictGetValNF(i, &fontRef); - if (fontRef.isRef()) + if (fontRef->isRef()) copyFont(obj->dictGetKey(i), &fontRef); else pdftex_fail("pdf inclusion: invalid font in reference type <%s>", - fontRef.getTypeName()); - fontRef.free(); + fontRef->getTypeName()); } pdf_puts(">>\n"); } static void copyOtherResources(Object *obj, char *key) { - Object obj1; + PdfObject obj1; int i, l; if (!obj->isDict()) pdftex_fail("pdf inclusion: invalid other resources dict type <%s>", @@ -288,20 +373,20 @@ pdf_puts(" << "); for (i = 0, l = obj->dictGetLength(); i < l; ++i) { obj->dictGetValNF(i, &obj1); - if (obj1.isRef()) { - copyName(obj->dictGetKey(i)); - pdf_printf(" %d 0 R ", addOther(obj1.getRef())); - } - else + copyName(obj->dictGetKey(i)); + if (obj1->isRef()) + pdf_printf(" %d 0 R ", addOther(obj1->getRef())); + else { + pdf_puts(" "); copyObject(&obj1); - obj1.free(); + } } pdf_puts(">>\n"); } static void copyObject(Object *obj) { - Object obj1; + PdfObject obj1; int i, l, c; Ref ref; char *p; @@ -354,10 +439,9 @@ pdf_puts("["); for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { obj->arrayGetNF(i, &obj1); - if (!obj1.isName()) + if (!obj1->isName()) pdf_puts(" "); copyObject(&obj1); - obj1.free(); } pdf_puts("]"); } @@ -367,11 +451,10 @@ pdf_puts(">>"); } else if (obj->isStream()) { - obj1.initDict(obj->getStream()->getDict()); + obj1->initDict(obj->getStream()->getDict()); obj->getStream()->getDict()->incRef(); pdf_puts("<<\n"); copyDict(&obj1); - obj1.free(); pdf_puts(">>\n"); pdf_puts("stream\n"); copyStream(obj->getStream()->getBaseStream()); @@ -394,28 +477,26 @@ static void writeRefs() { - Object obj1; - InObj *r, *n; + PdfObject obj1; + InObj *r; for (r = inObjList; r != 0; r = r->next) { - zpdfbeginobj(r->num); - xref->fetch(r->ref.num, r->ref.gen, &obj1); - if (r->type == objFont || r->type == objFontDesc) - copyFontDict(&obj1, r); - else - copyObject(&obj1); - pdf_puts("\n"); - pdfendobj(); - obj1.free(); - } - for (r = inObjList; r != 0; r = n) { - n = r->next; - delete r; + if (!r->written) { + r->written = 1; + zpdfbeginobj(r->num); + xref->fetch(r->ref.num, r->ref.gen, &obj1); + if (r->type == objFont || r->type == objFontDesc) + copyFontDict(&obj1, r); + else + copyObject(&obj1); + pdf_puts("\n"); + pdfendobj(); + } } } static void writeEncodings() { - UsedEncoding *n, *r; + UsedEncoding *r, *n; char *glyphNames[MAX_CHAR_CODE + 1], *s; int i; for (r = encodingList; r != 0; r = r->next) { @@ -433,31 +514,53 @@ } } -integer read_pdf_info(char *image_name, integer page_num) +// Returns the page number. +integer read_pdf_info(char *image_name, char *page_name, integer page_num) { - PDFDoc *doc; - GString *docName; + PdfDocument *pdf_doc; Page *page; + int rotate; // initialize if (!isInit) { - initParams(xpdfConfigFile); + // We should better not call xpdf's initParams, which would + // read $HOME/.xpdfrc to find external font files. There is + // no good reason for pdftex to have a hidden dependence on + // .xpdfrc, and we don't want the output PDF to depend on its + // contents. The following four lines replace the call to + // initParams(). + fontPath = (char **) gmalloc(sizeof(char *)); + fontPath[0] = 0; + devFontMap = (DevFontMapEntry *) gmalloc(sizeof(DevFontMapEntry)); + devFontMap[0].pdfFont = 0; + // initParams(xpdfConfigFile); errorInit(); isInit = gTrue; } // open PDF file - xref = 0; - docName = new GString(image_name); - doc = new PDFDoc(docName); - if (!doc->isOk() || !doc->okToPrint()) - pdftex_fail("xpdf: reading PDF image failed"); - epdf_doc = (void *)doc; - epdf_xref = (void *)xref; - epdf_num_pages = doc->getCatalog()->getNumPages(); - if (page_num <= 0 || page_num > epdf_num_pages) - pdftex_fail("pdf inclusion: required page does not exists <%i>", - epdf_num_pages); + pdf_doc = find_add_document(image_name); + epdf_doc = (void *) pdf_doc; + epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages(); + if (page_name) { + // get page by name + GString name(page_name); + LinkDest *link = pdf_doc->doc->findDest(&name); + if (link == 0 || !link->isOk()) + pdftex_fail("pdf inclusion: invalid destination <%s>", + page_name); + Ref ref = link->getPageRef(); + page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen); + if (page_num == 0) + pdftex_fail("pdf inclusion: destination is not a page <%s>", + page_name); + delete link; + } else { + // get page by number + if (page_num <= 0 || page_num > epdf_num_pages) + pdftex_fail("pdf inclusion: required page does not exist <%i>", + epdf_num_pages); + } // get the required page - page = doc->getCatalog()->getPage(page_num); + page = pdf_doc->doc->getCatalog()->getPage(page_num); if (page->isCropped()) { epdf_width = page->getCropX2() - page->getCropX1(); epdf_height = page->getCropY2() - page->getCropY1(); @@ -470,97 +573,159 @@ epdf_orig_x = page->getX1(); epdf_orig_y = page->getY1(); } - return 0; + rotate = page->getRotate(); + // handle page rotation and adjust dimens as needed + if (rotate != 0) { + if (rotate % 90 == 0) { + // handle only the simple case: multiple of 90s. + // these are the only values allowed according to the + // reference (v1.3, p.78). + // 180 needs no special treatment here + register float f; + switch (rotate) { + case 90: f = epdf_height; epdf_height = epdf_width; epdf_width = f; break; + case 270: f = epdf_height; epdf_height = epdf_width; epdf_width = f; break; + } + } + } + pdf_doc->xref = xref; + return page_num; } void write_epdf(void) { Page *page; - Object contents, obj1, obj2; + PdfObject contents, obj1, obj2; char *key; int i, l; - xref = (XRef *)epdf_xref; - page = ((PDFDoc *)epdf_doc)->getCatalog()->getPage(epdf_selected_page); - inObjList = 0; + int rotate; + double scale[6] = {0, 0, 0, 0, 0, 0}; + PdfDocument *pdf_doc = (PdfDocument *) epdf_doc; + xref = pdf_doc->xref; + inObjList = pdf_doc->inObjList; encodingList = 0; + page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page); + rotate = page->getRotate(); // write the Page header pdf_puts("/Type /XObject\n"); pdf_puts("/Subtype /Form\n"); pdf_puts("/FormType 1\n"); - pdf_puts("/Matrix [1 0 0 1 0 0]\n"); + // handle page rotation + if (rotate != 0) { + if (rotate % 90 == 0) { + // this handles only the simple case: multiple of 90s. + // these are the only values allowed according to the + // reference (v1.3, p.78). + // the image is rotated around its center. + // the /Rotate key is clockwise while the matrix is + // counterclockwise :-% + tex_printf (", page is rotated %d degrees", rotate); + switch (rotate) { + case 90: scale[1] = -1; scale[2] = 1; scale[5] = epdf_height; break; + case 180: scale[0] = scale[3] = -1; scale[4] = epdf_height; scale[5] = epdf_width; break; // width and height are exchanged + case 270: scale[1] = 1; scale[2] = -1; scale[4] = epdf_width; break; + } + } + } + else { + scale[0] = scale[3] = 1; + } + + pdf_printf("/Matrix [%.5g %.5g %.5g %.5g %.5g %.5g]\n", + scale[0], + scale[1], + scale[2], + scale[3], + scale[4], + scale[5]); + if (page->isCropped()) pdf_printf("/BBox [%.5g %.5g %.5g %.5g]\n", - page->getCropX1(), - page->getCropY1(), - page->getCropX2(), - page->getCropY2()); + page->getCropX1(), + page->getCropY1(), + page->getCropX2(), + page->getCropY2()); else pdf_printf("/BBox [%.5g %.5g %.5g %.5g]\n", - page->getX1(), - page->getY1(), - page->getX2(), - page->getY2()); + page->getX1(), + page->getY1(), + page->getX2(), + page->getY2()); // write the Resources dictionary - obj1.initDict(page->getResourceDict()); + obj1->initDict(page->getResourceDict()); page->getResourceDict()->incRef(); - if (!obj1.isDict()) + if (!obj1->isDict()) pdftex_fail("pdf inclusion: invalid resources dict type <%s>", - obj1.getTypeName()); + obj1->getTypeName()); pdf_puts("/Resources <<\n"); - for (i = 0, l = obj1.dictGetLength(); i < l; ++i) { - obj1.dictGetVal(i, &obj2); - key = obj1.dictGetKey(i); + for (i = 0, l = obj1->dictGetLength(); i < l; ++i) { + obj1->dictGetVal(i, &obj2); + key = obj1->dictGetKey(i); if (strcmp("Font", key) == 0) copyFontResources(&obj2); else if (strcmp("ProcSet", key) == 0) copyProcSet(&obj2); else copyOtherResources(&obj2, key); - obj2.free(); } - obj1.free(); pdf_puts(">>\n"); // write the page contents page->getContents(&contents); - if (contents.isStream()) { - obj1.initDict(contents.getStream()->getDict()); - contents.getStream()->getDict()->incRef(); + if (contents->isStream()) { + obj1->initDict(contents->getStream()->getDict()); + contents->getStream()->getDict()->incRef(); copyDict(&obj1); pdf_puts(">>\nstream\n"); - copyStream(contents.getStream()->getBaseStream()); + copyStream(contents->getStream()->getBaseStream()); pdf_puts("endstream\n"); pdfendobj(); - obj1.free(); } - else if (contents.isArray()) { + else if (contents->isArray()) { pdfbeginstream(); - for (i = 0, l = contents.arrayGetLength(); i < l; ++i) { - contents.arrayGet(i, &obj1); - copyStream(obj1.getStream()); - obj1.free(); + for (i = 0, l = contents->arrayGetLength(); i < l; ++i) { + contents->arrayGet(i, &obj1); + copyStream(obj1->getStream()); } pdfendstream(); } else pdftex_fail("pdf inclusion: invalid page contents type <%s>", - contents.getTypeName()); - contents.free(); + contents->getTypeName()); // write out all indirect objects writeRefs(); - // write out all used encodings + // write out all used encodings (and delete list) writeEncodings(); + // save object list, xref + pdf_doc->inObjList = inObjList; + pdf_doc->xref = xref; } +// Called when an image has been written and it's resources in +// image_tab are freed. We cannot deallocate the PdfDocument yet, as +// future pages of the same document may be embedded. As an +// optimization, we do delete it if it's a one-page document. void epdf_delete() { - xref = (XRef *)epdf_xref; - delete (PDFDoc *)epdf_doc; + PdfDocument *pdf_doc = (PdfDocument *) epdf_doc; + xref = pdf_doc->xref; + if (pdf_doc->doc->getCatalog()->getNumPages() == 1) + delete_document(pdf_doc); } +// Called when PDF embedding system is finalized. +// Now deallocate all remaining PdfDocuments. void epdf_check_mem() { if (isInit) { - freeParams(); + PdfDocument *p, *n; + for (p = pdfDocuments; p; p = n) { + n = p->next; + delete_document(p); + } + // see above for initParams + gfree(fontPath); + gfree(devFontMap); + // freeParams(); Object::memCheck(errFile); gMemReport(errFile); } --- teTeX-1.0/src/texk/web2c/pdftexdir/ptexlib.h.crypt 2000-12-19 03:35:17.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/ptexlib.h 2002-11-11 15:59:08.000000000 -0800 @@ -136,7 +136,7 @@ extern void pdf_puts(char *); extern void pdftex_fail(char *,...); extern void pdftex_warn(char *,...); -extern void setjobid(int, int, int, int); +extern void setjobid(int, int, int, int, int, int); extern void tex_printf(char *, ...); extern void writestreamlength(integer, integer); @@ -175,7 +175,7 @@ extern integer imagexres(integer); extern integer imagexres(integer); extern integer imageyres(integer); -extern integer readimage(strnumber, integer); +extern integer readimage(strnumber, integer, strnumber); extern void deleteimage(integer); extern void img_free(void) ; extern void updateimageprocset(integer); --- teTeX-1.0/src/texk/web2c/pdftexdir/utils.c.crypt 2000-09-10 07:58:09.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/utils.c 2002-11-11 15:59:08.000000000 -0800 @@ -151,18 +151,33 @@ va_end(args); } +/* Helper for pdftex_fail. */ +static void safe_print(char *str) +{ + 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(char *fmt,...) { va_list args; va_start(args, fmt); println(); - tex_printf("Error: %s", program_invocation_name); - if (cur_file_name) - tex_printf(" (file %s)", cur_file_name); - tex_printf(": "); + 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); - print(maketexstring(print_buf)); - flushstr(last_tex_string); + safe_print(print_buf); va_end(args); println(); exit(-1); @@ -189,7 +204,7 @@ static char cstrbuf[MAX_CSTRING_LEN]; char *p = cstrbuf; int i, l = strstart[s + 1] - strstart[s]; - check_buf(l, 1024); + check_buf(l, MAX_CSTRING_LEN); for (i = 0; i < l; i++) *p++ = strpool[i + strstart[s]]; *p = 0; @@ -207,7 +222,7 @@ return !*s && l == strstart[n + 1]; } -void setjobid(int year, int month, int day, int time) +void setjobid(int year, int month, int day, int time, int pdftexversion, int pdftexrevision) { extern string versionstring; /* from web2c/lib/version.c */ extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */ @@ -224,6 +239,15 @@ name_string, format_string, BANNER, versionstring, kpathsea_version_string); job_id_string = xstrdup(s); + + /* Initialize /Producer string */ + sprintf(s,"pdfTeX-%d.%d%s-pdfcrypt", pdftexversion/100, pdftexversion%100, &pdftexrevision); + pdfcryptversion = maketexstring(s); + + /* Initialize /CreationDate string */ + sprintf(s,"D:%4d%02d%02d%02d%02d00", year, month, day, time/60, time%60); + pdfcryptdate = maketexstring(s); + xfree(name_string); xfree(format_string); xfree(s); --- teTeX-1.0/src/texk/web2c/pdftexdir/writefont.c.crypt 2000-12-19 04:10:58.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/writefont.c 2002-11-11 15:59:08.000000000 -0800 @@ -216,7 +216,9 @@ static void write_fontdescriptor(void) { - int i; + int i, j; + char *buf, ch; + pdfbegindict(fm_cur->fd_objnum); /* font descriptor */ print_key(ASCENT_CODE, getcharheight(tex_font, 'h')); print_key(CAPHEIGHT_CODE, getcharheight(tex_font, 'H')); @@ -243,9 +245,37 @@ if (is_subsetted(fm_cur) && !is_truetype(fm_cur)) { cur_glyph_names = t1_glyph_names; pdf_puts("/CharSet ("); + + /* Initialize the key for the current string */ + if (pdfcrypting) pdfcrypt_initkey(); + + buf = (char *)gmalloc(64); for (i = 0; i <= MAX_CHAR_CODE; i++) if (pdfcharmarked(tex_font, i) && cur_glyph_names[i] != notdef) - pdf_printf("/%s", cur_glyph_names[i]); + { + buf[0] = 47; + for (j = 0; cur_glyph_names[i][j]; j++) { + buf[j+1] = cur_glyph_names[i][j]; + buf[j+2] = 0; + } + if (pdfcrypting) + for (j = 0; buf[j]; j++) { + ch = pdfcrypt_byte(buf[j]); + switch (ch) { + case 0: + case 13: + case 14: pdf_printf("\\%03o", ch); break; + case 40: + case 41: + case 92: pdf_printf("\\%c", ch); break; + default: pdf_printf("%c", ch); + } + } + else + pdf_printf("%s", buf); + } + gfree(buf); + pdf_puts(")\n"); } if (is_truetype(fm_cur)) --- teTeX-1.0/src/texk/web2c/pdftexdir/writeimg.c.crypt 2000-06-28 06:06:03.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/writeimg.c 2002-11-11 15:59:08.000000000 -0800 @@ -15,7 +15,6 @@ integer epdf_selected_page; integer epdf_num_pages; void *epdf_doc; -void *epdf_xref; static integer new_image_entry(void) { @@ -95,10 +94,15 @@ return img_pages(img); } -integer readimage(strnumber s, integer page_num) +integer readimage(strnumber s, integer page_num, strnumber page_name) { char *image_suffix; + char *dest = 0; integer img = new_image_entry(); + /* need to allocate new string as makecstring's buffer is + already used by cur_file_name */ + if (page_name != 0) + dest = strdup(makecstring(page_name)); cur_file_name = makecstring(s); img_name(img) = kpse_find_file(cur_file_name, kpse_tex_format, true); if (img_name(img) == 0) @@ -108,14 +112,13 @@ if (strcasecmp(image_suffix, ".pdf") == 0) { img_type(img) = IMAGE_TYPE_PDF; pdf_ptr(img) = xtalloc(1, pdf_image_struct); - read_pdf_info(img_name(img), page_num); + page_num = read_pdf_info(img_name(img), dest, page_num); img_width(img) = bp2int(epdf_width); img_height(img) = bp2int(epdf_height); img_pages(img) = epdf_num_pages; pdf_ptr(img)->orig_x = bp2int(epdf_orig_x); pdf_ptr(img)->orig_y = bp2int(epdf_orig_y); pdf_ptr(img)->selected_page = page_num; - pdf_ptr(img)->xref = epdf_xref; pdf_ptr(img)->doc = epdf_doc; } else if (strcasecmp(image_suffix, ".png") == 0) { @@ -140,6 +143,7 @@ #endif else pdftex_fail("unknown type of image"); + xfree(dest); cur_file_name = 0; return img; } @@ -161,7 +165,6 @@ break; #endif case IMAGE_TYPE_PDF: - epdf_xref = pdf_ptr(img)->xref; epdf_doc = pdf_ptr(img)->doc; epdf_selected_page = pdf_ptr(img)->selected_page; write_epdf(); @@ -177,7 +180,6 @@ { switch (img_type(img)) { case IMAGE_TYPE_PDF: - epdf_xref = pdf_ptr(img)->xref; epdf_doc = pdf_ptr(img)->doc; epdf_delete(); break; --- teTeX-1.0/src/texk/web2c/pdftexdir/writejpg.c.crypt 2000-08-23 13:27:27.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/writejpg.c 2002-11-11 15:59:08.000000000 -0800 @@ -206,7 +206,9 @@ (int)jpg_ptr(img)->color_space); } pdf_puts("/Filter /DCTDecode\n>>\nstream\n"); + if (pdfcrypting) pdfcrypt_initkey(); for (l = jpg_ptr(img)->length, f = jpg_ptr(img)->file; l > 0; l--) - pdfout(xgetc(f)); + if (pdfcrypting) pdfout(pdfcrypt_byte(xgetc(f))); + else pdfout( xgetc(f) ); pdf_puts("endstream\nendobj\n"); } --- teTeX-1.0/src/texk/web2c/pdftexdir/writezip.c.crypt 2000-06-28 06:06:04.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/writezip.c 2002-11-11 15:59:08.000000000 -0800 @@ -15,6 +15,23 @@ void writezip(boolean finish) { int err; + int i; + + if ( (pdfstreamlength == 0) && (pdfcrypting) ) { + /* Initialize key for current stream */ + pdfcrypt_initkey(); + } + if (!fixedcompresslevel) { + if (pdfptr) { + if (pdfcrypting) + for (i = 0; i < pdfptr; i++) + pdfbuf[i] = pdfcrypt_byte(pdfbuf[i]); + pdfgone += xfwrite(pdfbuf, 1, pdfptr, pdffile); + pdfstreamlength += pdfptr; + } + return; + } + cur_file_name = NULL; if (pdfstreamlength == 0) { c_stream.zalloc = (alloc_func)0; @@ -28,6 +45,9 @@ c_stream.avail_in = pdfptr; for(;;) { if (c_stream.avail_out == 0) { + if (pdfcrypting) + for (i = 0; i < ZIP_BUF_SIZE; i++) + zipbuf[i] = pdfcrypt_byte(zipbuf[i]); pdfgone += xfwrite(zipbuf, 1, ZIP_BUF_SIZE, pdffile); c_stream.next_out = zipbuf; c_stream.avail_out = ZIP_BUF_SIZE; @@ -41,7 +61,12 @@ } if (finish) { if (c_stream.avail_out < ZIP_BUF_SIZE) /* at least one byte has been output */ + { + if (pdfcrypting) + for (i = 0; i < ZIP_BUF_SIZE - c_stream.avail_out; i++) + zipbuf[i] = pdfcrypt_byte(zipbuf[i]); pdfgone += xfwrite(zipbuf, 1, ZIP_BUF_SIZE - c_stream.avail_out, pdffile); + } check_err(deflateEnd(&c_stream), "deflateEnd"); xfflush(pdffile); } --- teTeX-1.0/src/texk/web2c/pdftexdir/depend.mk.crypt 2000-06-28 06:06:01.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/depend.mk 2002-11-11 15:59:08.000000000 -0800 @@ -193,5 +193,7 @@ $(srcdir)/../../../libs/xpdf/xpdf/Link.h \ $(srcdir)/../../../libs/xpdf/xpdf/Error.h \ $(srcdir)/epdf.h +pdfcrypt.o: $(srcdir)/pdfcrypt.c \ + $(srcdir)/pdfcrypt.h ttf2afm.o: $(srcdir)/ttf2afm.c \ $(srcdir)/macnames.c --- teTeX-1.0/src/texk/web2c/pdftexdir/Makefile.in.crypt 2000-06-28 06:06:01.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/Makefile.in 2002-11-11 15:59:08.000000000 -0800 @@ -33,7 +33,7 @@ OBJS = epdf.o mapfile.o papersiz.o utils.o config.o vfpacket.o pkin.o \ writefont.o writet1.o writet3.o writezip.o writeenc.o writettf.o \ -writejpg.o writepng.o writetif.o writeimg.o pdftoepdf.o +writejpg.o writepng.o writetif.o writeimg.o pdftoepdf.o pdfcrypt.o all: libpdf.a --- teTeX-1.0/src/texk/web2c/pdftexdir/tex.pch.crypt 2000-10-27 10:16:38.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/tex.pch 2002-11-11 15:59:08.000000000 -0800 @@ -248,6 +248,7 @@ setup_bound_var (0)('hash_extra')(hash_extra); setup_bound_var (65536)('obj_tab_size')(obj_tab_size); setup_bound_var (65536)('pdf_mem_size')(pdf_mem_size); + setup_bound_var (20000)('dest_names_size')(dest_names_size); @z @x [51.2] @@ -257,6 +258,7 @@ const_chk (hash_extra); const_chk (obj_tab_size); const_chk (pdf_mem_size); + const_chk (dest_names_size); if error_line > ssup_error_line then error_line := ssup_error_line; @z @@ -266,6 +268,7 @@ xmalloc_array (hyph_link , hyph_size); xmalloc_array (obj_tab, obj_tab_size); xmalloc_array (pdf_mem, pdf_mem_size); + xmalloc_array (dest_names, dest_names_size); @z @x (WEB2C!) --- teTeX-1.0/src/texk/web2c/pdftexdir/writet1.c.crypt 2002-11-11 15:58:33.000000000 -0800 +++ teTeX-1.0/src/texk/web2c/pdftexdir/writet1.c 2002-11-11 15:59:08.000000000 -0800 @@ -63,6 +63,7 @@ #define t1_scan_keys() #define update_builtin_enc(font, glyph_names) #define embed_all_glyphs(tex_font) false +#undef pdfmovechars #ifdef SHIFTLOWCHARS #define t1_char(c) T1Char(c) #define pdfmovechars 1 @@ -70,8 +71,9 @@ #define t1_char(c) c #define pdfmovechars 0 #endif /* SHIFTLOWCHARS */ -#define extra_charset() 0 +#define extra_charset() dvips_extra_charset #define make_subset_tag(a, b) +static char *dvips_extra_charset ; extern FILE *bitfile ; extern FILE *search(); static char *cur_file_name; @@ -224,7 +226,7 @@ }; /* Which begin/end token set do we use for the font? */ -static int cs_token_choice = 0; +static int cs_token_choice = -1; static boolean cs_tokens_found = false; static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic; @@ -1105,8 +1107,6 @@ { cs_token_choice = 2; cs_tokens_found = true; } else if (t1_buf_prefix(" -|") && t1_buf_suffix("noaccess put", q)) { cs_token_choice = 3; cs_tokens_found = true; } - else - { cs_token_choice = -1; cs_tokens_found = false; } } ptr->len = q - t1_buf; ptr->cslen = t1_cslen; @@ -1360,7 +1360,7 @@ static void t1_subset_ascii_part(void) { - int i; + int i, j; save_offset(); t1_getline(); while (!t1_prefix("/Encoding")) { @@ -1381,10 +1381,17 @@ t1_puts("/Encoding StandardEncoding def\n"); else { t1_puts("/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"); - for (i = 0; i <= MAX_CHAR_CODE; i++) - if (is_used_char(i) && t1_glyph_names[i] != notdef) - t1_printf("dup %i /%s put\n", (int)t1_char(i), - t1_glyph_names[i]); + for (i = 0, j = 0; i <= MAX_CHAR_CODE; i++) { + if (is_used_char(i) && t1_glyph_names[i] != notdef) { + j++; + t1_printf("dup %i /%s put\n", (int)t1_char(i), t1_glyph_names[i]); + } + } + /* We didn't mark anything for the Encoding array. */ + /* We add "dup 0 /.notdef put" for compatibility */ + /* with Acrobat 5.0. */ + if (j == 0) + t1_puts("dup 0 /.notdef put\n"); t1_puts("readonly def\n"); } do { @@ -1573,6 +1580,10 @@ sprintf(t1_line, "%s", line_end); t1_line_ptr = eol(t1_line); t1_putline(); + if (is_subr) { + cs_token_choice = -1; + cs_tokens_found = false; + } xfree(tab); xfree(start_line); xfree(line_end); @@ -1645,7 +1656,7 @@ t1_mark_glyphs(); if (subr_tab != 0) { if (cs_token_choice == -1) - pdftex_fail("This Type 1 font uses an unknown subroutine begin/end token pair."); + pdftex_fail("This Type 1 font uses mismatched subroutine begin/end token pairs."); t1_subr_flush(); } for (cs_count = 0, ptr = cs_tab; ptr < cs_ptr; ptr++) @@ -1734,5 +1745,21 @@ for (i = 0; i <= MAX_CHAR_CODE; i++) if (ext_glyph_names[i] != notdef) free(ext_glyph_names[i]); + return 1 ; /* note: there *is* no unsuccessful return */ +} +boolean t1_subset_2(char *fontfile, unsigned char *g, char *extraGlyphs) +{ + int i; + for (i = 0; i <= MAX_CHAR_CODE; i++) + ext_glyph_names[i] = notdef; + grid = g; + cur_file_name = fontfile; + hexline_length = 0; + dvips_extra_charset = extraGlyphs ; + writet1(); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (ext_glyph_names[i] != notdef) + free(ext_glyph_names[i]); + return 1 ; /* note: there *is* no unsuccessful return */ } #endif /* not pdfTeX */ --- teTeX-1.0/src/texk/web2c/pdftexdir/config.c.crypt 2001-04-13 07:51:43.000000000 -0700 +++ teTeX-1.0/src/texk/web2c/pdftexdir/config.c 2002-11-12 16:29:51.000000000 -0800 @@ -39,6 +39,9 @@ {cfgdestmargincode, "dest_margin", 0, false}, {cfgthreadmargincode, "thread_margin", 0, false}, {cfgpdf12compliantcode, "pdf12_compliant", 0, false}, + {cfgpdf13compliantcode, "pdf13_compliant", 0, false}, + {cfgpdf14compliantcode, "pdf14_compliant", 0, false}, + {cfgcryptkeybits, "crypt_key_bits", 128, false}, {0, 0, 0, false} }; @@ -73,7 +76,7 @@ void readconfigfile() { - int c, res, sign; + int c, res, sign, newval; cfg_entry *ce; char cfg_line[CFG_BUF_SIZE], *p, *r; set_cur_file_name(config_name); @@ -124,20 +127,28 @@ case cfguniqueresnamecode: case cfgprotrudecharscode: case cfgpdf12compliantcode: + case cfgpdf13compliantcode: + case cfgpdf14compliantcode: + case cfgcryptkeybits: if (*p == '-') { p++; sign = -1; } else sign = 1; - ce->value = myatol(&p); + newval = myatol(&p); if (ce->value == -1) { remove_eol(p, cfg_line); pdftex_warn("invalid parameter value in config filecode: `%s'", cfg_line); - ce->value = 0; } + else if (ce->code == cfgcryptkeybits + && (ce->value % 8 != 0 || ce->value < 40 + || ce->value > 128)) { + remove_eol(p, cfg_line); + pdftex_warn("invalid encryption key bit length: `%s'", cfg_line); + } else - ce->value *= sign; + ce->value = newval * sign; break; case cfghorigincode: case cfgvorigincode: @@ -161,6 +172,13 @@ kpse_init_prog("pdfTeX", (unsigned)res, NULL, NULL); if (mapfiles == 0) mapfiles = xstrdup("psfonts.map\n"); + if (cfgpar(cfgpdf12compliantcode) != 0 + || cfgpar(cfgpdf13compliantcode) != 0) { + if (cfgpar(cfgcryptkeybits) != 0 && cfgpar(cfgcryptkeybits) != 40) { + pdftex_warn("invalid encryption key len for PDF version: `%ld'", (long)cfgpar(cfgcryptkeybits)); + cfg_tab[cfgcryptkeybits].value = 0; + } + } } boolean iscfgtruedimen(integer code)