diff -urN xpdf-0.7a/xpdf/Makefile.in.orig xpdf-0.7a/xpdf/Makefile.in --- xpdf-0.7a/xpdf/Makefile.in.orig Tue Feb 17 14:58:30 1998 +++ xpdf-0.7a/xpdf/Makefile.in Sun May 17 13:21:36 1998 @@ -35,7 +35,7 @@ XPDF_OBJS = Array.o Catalog.o Dict.o Error.o Gfx.o GfxFont.o \ GfxState.o Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \ Parser.o PDFDoc.o PSOutputDev.o Stream.o TextOutputDev.o \ - XOutputDev.o XRef.o xpdf.o + XOutputDev.o XRef.o xpdf.o md5.o rc4.o XPDF_LIBS = -L$(LTKDIR) -lLTK -L$(GOODIR) -lGoo $(XLIBS) -lm xpdf$(EXE): $(XPDF_OBJS) @@ -49,7 +49,7 @@ PDFTOPS_OBJS = Array.o Catalog.o Dict.o Error.o Gfx.o GfxFont.o \ GfxState.o Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \ - Parser.o PDFDoc.o PSOutputDev.o Stream.o XRef.o pdftops.o + Parser.o PDFDoc.o PSOutputDev.o Stream.o XRef.o pdftops.o md5.o rc4.o PDFTOPS_LIBS = -L$(GOODIR) -lGoo -lm pdftops$(EXE): $(PDFTOPS_OBJS) @@ -60,7 +60,7 @@ PDFTOTEXT_OBJS = Array.o Catalog.o Dict.o Error.o Gfx.o GfxFont.o \ GfxState.o Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \ - Parser.o PDFDoc.o TextOutputDev.o Stream.o XRef.o pdftotext.o + Parser.o PDFDoc.o TextOutputDev.o Stream.o XRef.o pdftotext.o md5.o rc4.o PDFTOTEXT_LIBS = -L$(GOODIR) -lGoo -lm pdftotext$(EXE): $(PDFTOTEXT_OBJS) diff -urN xpdf-0.7a/xpdf/GfxFont.cc.orig xpdf-0.7a/xpdf/GfxFont.cc --- xpdf-0.7a/xpdf/GfxFont.cc.orig Tue Feb 17 14:58:22 1998 +++ xpdf-0.7a/xpdf/GfxFont.cc Sun May 17 13:22:02 1998 @@ -351,7 +351,7 @@ hex = gFalse; for (code = 0; code < 256; ++code) { if ((charName = encoding->getCharName(code))) { - if ((charName[0] == 'C' || charName[0] == 'G') && + if ((charName[0] == 'B' || charName[0] == 'C' || charName[0] == 'G') && strlen(charName) == 3 && ((charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F') || @@ -366,7 +366,8 @@ if ((charName = encoding->getCharName(code))) { n = strlen(charName); i = -1; - if (hex && n == 3 && (charName[0] == 'C' || charName[0] == 'G') && + if (hex && n == 3 && + (charName[0] == 'B' || charName[0] == 'C' || charName[0] == 'G') && isxdigit(charName[1]) && isxdigit(charName[2])) sscanf(charName+1, "%x", &i); else if (!hex && n >= 2 && n <= 3 && diff -urN xpdf-0.7a/xpdf/Parser.cc.orig xpdf-0.7a/xpdf/Parser.cc --- xpdf-0.7a/xpdf/Parser.cc.orig Tue Feb 17 15:02:43 1998 +++ xpdf-0.7a/xpdf/Parser.cc Sun May 17 13:31:22 1998 @@ -16,6 +16,8 @@ #include "Dict.h" #include "Parser.h" #include "Error.h" +#include "md5.h" +#include "XRef.h" Parser::Parser(Lexer *lexer1) { lexer = lexer1; @@ -158,4 +160,40 @@ buf2.initNull(); else lexer->getObj(&buf2); +} + +Object *Parser::getEncryptedObj(Object *obj, int num, int gen) { + Stream *str1, *str2; + MD5 context; + RC4KEY rc4Key; + GString MD5Key; + GString Key; + + getObj(obj); + // check for obj type + if (obj->isStream()) { + // enable Decryption on base File Stream + str2 = obj->getStream(); + do { + str1 = str2; + str2 = str1->getBaseStream(); + } while (str1 != str2); + + Key.append(xref->getEncryptionKey()); + Key.append((char)( num & 0xff)); + Key.append((char)((num >> 8) & 0xff)); + Key.append((char)((num >>16) & 0xff)); + Key.append((char)( gen & 0xff)); + Key.append((char)((gen >> 8) & 0xff)); + context.update((unsigned char *)Key.getCString(), 10); + context.finalize(); + MD5Key.clear(); + MD5Key.append((char *)context.raw_digest(), 10); + + // determine rc4Key + rc4ExpandKey(&rc4Key, (unsigned char *)MD5Key.getCString(), 10); + + str1->enableEncryption(&rc4Key); + } + return obj; } diff -urN xpdf-0.7a/xpdf/Parser.h.orig xpdf-0.7a/xpdf/Parser.h --- xpdf-0.7a/xpdf/Parser.h.orig Tue Feb 17 15:02:48 1998 +++ xpdf-0.7a/xpdf/Parser.h Sun May 17 13:31:53 1998 @@ -30,6 +30,7 @@ // Get the next object from the input stream. Object *getObj(Object *obj); + Object *getEncryptedObj(Object *obj, int num, int gen); // Get stream. Stream *getStream() { return lexer->getStream(); } diff -urN xpdf-0.7a/xpdf/Stream.cc.orig xpdf-0.7a/xpdf/Stream.cc --- xpdf-0.7a/xpdf/Stream.cc.orig Tue Feb 17 15:03:08 1998 +++ xpdf-0.7a/xpdf/Stream.cc Sun May 17 13:34:03 1998 @@ -215,6 +215,7 @@ bufPos = start; savePos = -1; dict = *dict1; + encryption = gFalse; } FileStream::~FileStream() { @@ -243,6 +244,9 @@ n = 256; n = fread(buf, 1, n, f); bufEnd = buf + n; + if (encryption == gTrue) { + rc4Crypt(&rc4Key, (unsigned char *)buf, n); + } if (bufPtr >= bufEnd) return gFalse; return gTrue; @@ -291,6 +295,13 @@ return gFalse; } return gTrue; +} + +void FileStream::enableEncryption(RC4KEY *prc4Key) +{ + // prepary RC4 key + rc4Key = *prc4Key; + encryption = gTrue; } //------------------------------------------------------------------------ diff -urN xpdf-0.7a/xpdf/Stream.h.orig xpdf-0.7a/xpdf/Stream.h --- xpdf-0.7a/xpdf/Stream.h.orig Tue Feb 17 15:03:18 1998 +++ xpdf-0.7a/xpdf/Stream.h Sun May 17 13:37:00 1998 @@ -15,9 +15,14 @@ #include #include +#include #include "Object.h" +//extern "C" { +#include "rc4.h" +//} + //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -75,6 +80,8 @@ // Returns the new stream. Stream *addFilters(Object *dict); + virtual void enableEncryption(RC4KEY *rc4Key) {error(-1, "No FileStream, no decryption");}; + private: Stream *makeFilter(char *name, Stream *str, Object *params); @@ -112,8 +119,12 @@ private: + void enableEncryption(RC4KEY *rc4Key); + GBool fillBuf(); + RC4KEY rc4Key; + GBool encryption; FILE *f; int start; int length; diff -urN xpdf-0.7a/xpdf/XRef.cc.orig xpdf-0.7a/xpdf/XRef.cc --- xpdf-0.7a/xpdf/XRef.cc.orig Sun Feb 22 10:57:23 1998 +++ xpdf-0.7a/xpdf/XRef.cc Sun May 17 13:48:56 1998 @@ -22,6 +22,10 @@ #include "Dict.h" #include "Error.h" #include "XRef.h" +#include "md5.h" +//extern "C" { +#include "rc4.h" +//} //------------------------------------------------------------------------ @@ -46,6 +50,7 @@ ok = gTrue; size = 0; entries = NULL; + encrypted = gFalse; // get rid of old xref (otherwise it will try to fetch the Root object // in the new document, using the old xref) @@ -91,10 +96,19 @@ xref = this; // check for encryption + m_okToPrint = gTrue; + m_okToCopy = gTrue; + m_okToChange = gTrue; + m_okToAddNotes = gTrue; if (checkEncrypted()) { - ok = gFalse; - xref = oldXref; - return; + // ok = gFalse; + // xref = oldXref; + // return; + if (setupDecryption() == gFalse) { + ok = gFalse; + xref = oldXref; + return; + } } } @@ -380,26 +394,38 @@ } GBool XRef::checkEncrypted() { - Object obj; - GBool encrypted; - - trailerDict.dictLookup("Encrypt", &obj); - if ((encrypted = !obj.isNull())) { - error(-1, "PDF file is encrypted and cannot be displayed"); - error(-1, "* Decryption support is currently not included in xpdf"); - error(-1, "* due to legal restrictions: the U.S.A. still has bogus"); - error(-1, "* export controls on cryptography software."); - } - obj.free(); + // Object obj; + // GBool encrypted; + // + // trailerDict.dictLookup("Encrypt", &obj); + // if ((encrypted = !obj.isNull())) { + // error(-1, "PDF file is encrypted and cannot be displayed"); + // error(-1, "* Decryption support is currently not included in xpdf"); + // error(-1, "* due to legal restrictions: the U.S.A. still has bogus"); + // error(-1, "* export controls on cryptography software."); + // } + // obj.free(); + trailerDict.dictLookup("Encrypt", &encryptionDict); + encrypted = encryptionDict.isDict(); return encrypted; } GBool XRef::okToPrint() { - return gTrue; + // return gTrue; + return m_okToPrint; } GBool XRef::okToCopy() { - return gTrue; + // return gTrue; + return m_okToCopy; +} + +GBool XRef::okToChange() { + return m_okToChange; +} + +GBool XRef::okToAddNotes() { + return m_okToAddNotes; } Object *XRef::fetch(int num, int gen, Object *obj) { @@ -424,7 +450,12 @@ if (obj1.isInt() && obj1.getInt() == num && obj2.isInt() && obj2.getInt() == gen && obj3.isCmd("obj")) { - parser->getObj(obj); + // parser->getObj(obj); + if (encrypted) { + parser->getEncryptedObj(obj, num, gen); + } else { + parser->getObj(obj); + } } else { obj->initNull(); } @@ -436,4 +467,164 @@ obj->initNull(); } return obj; +} + +GBool XRef::setupDecryption() { + Object obj; + GBool encrypted; + GBool passwordOk; + GString userPassword; + + // check filter + encryptionDict.dictLookupNF("Filter", &obj); + if (!obj.isName()) { + error(-1, "No filter specified, asume Standard filter"); + } else if (strcmp(obj.getName(), "Standard") != 0) { + error(-1, "File is encrypted with a non Standard Filter.\ +xpdf supports only the standard encryption filter"); + obj.free(); + return gFalse; + } + obj.free(); + + // check for no user password + userPassword.clear(); + if (checkUserPassword(&userPassword) == gFalse) { + // ask for user password + // ... + // check with user password + error(-1, "pdf file is encrypted with a user password.\ +xpdf does not support passwords please contact the author of the pdf file\ +and ask him for a non password encrypted version"); + return gFalse; + } + + // set permissions + // permissions + encryptionDict.dictLookupNF("P", &obj); + if (obj.isNull() || !obj.isInt()) { + error(-1, "No permissions specified"); + return gFalse; + } + int Permissions = obj.getInt(); + obj.free(); + m_okToPrint = Permissions & 0x04 ? gTrue : gFalse; + m_okToChange = Permissions & 0x08 ? gTrue : gFalse; + m_okToCopy = Permissions & 0x10 ? gTrue : gFalse; + m_okToAddNotes = Permissions & 0x20 ? gTrue : gFalse; + + return gTrue; +} + +GBool +XRef::checkUserPassword(GString *userPassword) +{ + GString preparedPassword; + RC4KEY rc4Key; + Object obj; + char localPassword[32]; + + if (preparePassword(userPassword, &preparedPassword) == gFalse) { + return gFalse; + } + if (MakeEncryptionKey(&preparedPassword, &encryptionKey) == gFalse) { + return gFalse; + } + + // get the User password + encryptionDict.dictLookupNF("U", &obj); + if (obj.isNull() || !obj.isString()) { + error(-1, "No user password specified"); + return gFalse; + } + memcpy(localPassword, obj.getString()->getCString(), 32); + obj.free(); + + // prepary RC4 key + rc4ExpandKey(&rc4Key, (unsigned char *)encryptionKey.getCString(), 5); + + // encrypt User password + rc4Crypt(&rc4Key, (unsigned char *)&localPassword[0], 32); + + // compare preparedPassword and decryptedPassword + for (int i=0; i<32; i++) { + if (localPassword[i] != preparedPassword.getChar(i)) { + // not equal + return gFalse; + } + } + // password OK + + return gTrue; +} + +GBool +XRef::MakeEncryptionKey(GString *password, GString *encryptionKey) +{ + MD5 context; + Object obj, obj1; + unsigned char Pkey[4]; + + context.update((unsigned char *)password->getCString(), 32); + + // others + // owner key + encryptionDict.dictLookupNF("O", &obj); + if (obj.isNull() || !obj.isString()) { + error(-1, "No owner password specified"); + return gFalse; + } + context.update((unsigned char *)obj.getString()->getCString(), 32); + obj.free(); + + // permissions + encryptionDict.dictLookupNF("P", &obj); + if (obj.isNull() || !obj.isInt()) { + error(-1, "No permissions specified"); + return gFalse; + } + int Permissions = obj.getInt(); + Pkey[0] = Permissions & 0xff; + Pkey[1] = (Permissions >> 8 ) & 0xff; + Pkey[2] = (Permissions >> 16) & 0xff; + Pkey[3] = (Permissions >> 24) & 0xff; + context.update(&Pkey[0], 4); + obj.free(); + + // first element from ID + trailerDict.dictLookupNF("ID", &obj); + if (obj.isNull() || !obj.isArray()) { + error(-1, "No ID specified"); + return gFalse; + } + obj.arrayGet(0, &obj1); + if (obj1.isNull() || !obj1.isString()) { + error(-1, "No ID elements specified"); + return gFalse; + } + context.update((unsigned char *)(obj1.getString()->getCString()), (int)(obj1.getString()->getLength())); + obj1.free(); + obj.free(); + + context.finalize(); + + encryptionKey->clear(); + encryptionKey->append((char *)context.raw_digest(), 5); + + return gTrue; +} + +GBool +XRef::preparePassword(GString *password, GString *preparedPassword) +{ + static char acFill[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}; + + preparedPassword->clear(); + preparedPassword->append(password); + preparedPassword->append(&acFill[0], 32); + + return gTrue; } diff -urN xpdf-0.7a/xpdf/XRef.h.orig xpdf-0.7a/xpdf/XRef.h --- xpdf-0.7a/xpdf/XRef.h.orig Tue Feb 17 15:03:48 1998 +++ xpdf-0.7a/xpdf/XRef.h Sun May 17 13:50:43 1998 @@ -45,10 +45,15 @@ // Are printing and copying allowed? If not, print an error message. GBool okToPrint(); GBool okToCopy(); + GBool okToChange(); + GBool okToAddNotes(); // Get catalog object. Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } + // get encryption key + GString *getEncryptionKey() { return &encryptionKey; }; + // Fetch an indirect reference. Object *fetch(int num, int gen, Object *obj); @@ -62,6 +67,19 @@ int rootNum, rootGen; // catalog dict GBool ok; // true if xref table is valid Object trailerDict; // trailer dictionary + + GBool m_okToPrint; + GBool m_okToCopy; + GBool m_okToChange; + GBool m_okToAddNotes; + Object encryptionDict; // encryption dictionary + GBool encrypted; + GString encryptionKey; + + GBool setupDecryption(); + GBool checkUserPassword(GString *userPassword); + GBool MakeEncryptionKey(GString *password, GString *encryptionKey); + GBool preparePassword(GString *password, GString *preparedPassword); int readTrailer(FileStream *str); GBool readXRef(FileStream *str, int *pos); diff -urN xpdf-0.7a/xpdf/config.h.orig xpdf-0.7a/xpdf/config.h --- xpdf-0.7a/xpdf/config.h.orig Tue Feb 17 14:58:24 1998 +++ xpdf-0.7a/xpdf/config.h Sun May 17 13:51:29 1998 @@ -14,7 +14,7 @@ //------------------------------------------------------------------------ // xpdf version -#define xpdfVersion "0.7a" +#define xpdfVersion "0.7a (encryption)" // supported PDF version #define pdfVersion "1.2" @@ -22,6 +22,7 @@ // copyright notice #define xpdfCopyright "Copyright \251 1996-1998 Derek B. Noonburg" +#define xpdfCopyright_Encryption "Encryption by Leo J.B. Smiers" // paper size (in points) for PostScript output // (eventually this will be configurable from the print dialog) diff -urN xpdf-0.7a/xpdf/md5.cc.orig xpdf-0.7a/xpdf/md5.cc --- xpdf-0.7a/xpdf/md5.cc.orig Thu Jan 1 10:00:00 1970 +++ xpdf-0.7a/xpdf/md5.cc Sat Apr 4 18:58:35 1998 @@ -0,0 +1,544 @@ +// MD5.CC - source code for the C++/object oriented translation and +// modification of MD5. + +// Translation and modification (c) 1995 by Mordechai T. Abzug + +// This translation/ modification is provided "as is," without express or +// implied warranty of any kind. + +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially +// copied from the disclaimer below). + +/* based on: + + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + + */ + + + + + + +#include "md5.h" + +#include +#include +#include + + + + +// MD5 simple initialization method + +MD5::MD5(){ + + init(); + +} + + + + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block, and updating the +// context. + +void MD5::update (uint1 *input, uint4 input_length) { + + uint4 input_index, buffer_index; + uint4 buffer_space; // how much space is left in buffer + + if (finalized){ // so we can't update! + cerr << "MD5::update: Can't update a finalized digest!" << endl; + return; + } + + // Compute number of bytes mod 64 + buffer_index = (unsigned int)((count[0] >> 3) & 0x3F); + + // Update number of bits + if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) + count[1]++; + + count[1] += ((uint4)input_length >> 29); + + + buffer_space = 64 - buffer_index; // how much space is left in buffer + + // Transform as many times as possible. + if (input_length >= buffer_space) { // ie. we have enough to fill the buffer + // fill the rest of the buffer and transform + memcpy (buffer + buffer_index, input, buffer_space); + transform (buffer); + + // now, transform each 64-byte piece of the input, bypassing the buffer + for (input_index = buffer_space; input_index + 63 < input_length; + input_index += 64) + transform (input+input_index); + + buffer_index = 0; // so we can buffer remaining + } + else + input_index=0; // so we can buffer the whole input + + + // and here we do the buffering: + memcpy(buffer+buffer_index, input+input_index, input_length-input_index); +} + + + +// MD5 update for files. +// Like above, except that it works on files (and uses above as a primitive.) + +void MD5::update(FILE *file){ + + unsigned char buffer[1024]; + int len; + + while (len=fread(buffer, 1, 1024, file)) + update(buffer, len); + + fclose (file); + +} + + + + + + +// MD5 update for istreams. +// Like update for files; see above. + +void MD5::update(istream& stream){ + + unsigned char buffer[1024]; + int len; + + while (stream.good()){ + stream.read(buffer, 1024); // note that return value of read is unusable. + len=stream.gcount(); + update(buffer, len); + } + +} + + + + + + +// MD5 update for ifstreams. +// Like update for files; see above. + +void MD5::update(ifstream& stream){ + + unsigned char buffer[1024]; + int len; + + while (stream.good()){ + stream.read(buffer, 1024); // note that return value of read is unusable. + len=stream.gcount(); + update(buffer, len); + } + +} + + + + + + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. + + +void MD5::finalize (){ + + unsigned char bits[8]; + unsigned int index, padLen; + static uint1 PADDING[64]={ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (finalized){ + cerr << "MD5::finalize: Already finalized this digest!" << endl; + return; + } + + // Save number of bits + encode (bits, count, 8); + + // Pad out to 56 mod 64. + index = (uint4) ((count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + update (PADDING, padLen); + + // Append length (before padding) + update (bits, 8); + + // Store state in digest + encode (digest, state, 16); + + // Zeroize sensitive information + memset (buffer, 0, sizeof(*buffer)); + + finalized=1; + +} + + + + +MD5::MD5(FILE *file){ + + init(); // must be called be all constructors + update(file); + finalize (); +} + + + + +MD5::MD5(istream& stream){ + + init(); // must called by all constructors + update (stream); + finalize(); +} + + + +MD5::MD5(ifstream& stream){ + + init(); // must called by all constructors + update (stream); + finalize(); +} + + + +unsigned char *MD5::raw_digest(){ + + uint1 *s = new uint1[16]; + + if (!finalized){ + cerr << "MD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" <> 8) & 0xff); + output[j+2] = (uint1) ((input[i] >> 16) & 0xff); + output[j+3] = (uint1) ((input[i] >> 24) & 0xff); + } +} + + + + +// Decodes input (unsigned char) into output (UINT4). Assumes len is +// a multiple of 4. +void MD5::decode (uint4 *output, uint1 *input, uint4 len){ + + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); +} + + + + + +// Note: Replace "for loop" with standard memcpy if possible. +void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){ + + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + + + +// Note: Replace "for loop" with standard memset if possible. +void MD5::memset (uint1 *output, uint1 value, uint4 len){ + + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = value; +} + + + +// ROTATE_LEFT rotates x left n bits. + +inline unsigned int MD5::rotate_left (uint4 x, uint4 n){ + return (x << n) | (x >> (32-n)) ; +} + + + + +// F, G, H and I are basic MD5 functions. + +inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){ + return (x & y) | (~x & z); +} + +inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){ + return (x & z) | (y & ~z); +} + +inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){ + return x ^ y ^ z; +} + +inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){ + return y ^ (x | ~z); +} + + + +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +// Rotation is separate from addition to prevent recomputation. + + +inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += F(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += G(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += H(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} + +inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += I(b, c, d) + x + ac; + a = rotate_left (a, s) +b; +} diff -urN xpdf-0.7a/xpdf/md5.h.orig xpdf-0.7a/xpdf/md5.h --- xpdf-0.7a/xpdf/md5.h.orig Thu Jan 1 10:00:00 1970 +++ xpdf-0.7a/xpdf/md5.h Sat Apr 4 18:58:36 1998 @@ -0,0 +1,109 @@ +// MD5.CC - source code for the C++/object oriented translation and +// modification of MD5. + +// Translation and modification (c) 1995 by Mordechai T. Abzug + +// This translation/ modification is provided "as is," without express or +// implied warranty of any kind. + +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially +// copied from the disclaimer below). + +/* based on: + + MD5.H - header file for MD5C.C + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +#include +#include +#include + +class MD5 { + +public: +// methods for controlled operation: + MD5 (); // simple initializer + void update (unsigned char *input, unsigned int input_length); + void update (istream& stream); + void update (FILE *file); + void update (ifstream& stream); + void finalize (); + +// constructors for special circumstances. All these constructors finalize +// the MD5 context. + MD5 (unsigned char *string); // digest string, finalize + MD5 (istream& stream); // digest stream, finalize + MD5 (FILE *file); // digest file, close, finalize + MD5 (ifstream& stream); // digest stream, close, finalize + +// methods to acquire finalized result + unsigned char *raw_digest (); // digest as a 16-byte binary array + char * hex_digest (); // digest as a 33-byte ascii-hex string + friend ostream& operator<< (ostream&, MD5 context); + + + +private: + +// first, some types: + typedef unsigned int uint4; // assumes integer is 4 words long + typedef unsigned short int uint2; // assumes short integer is 2 words long + typedef unsigned char uint1; // assumes char is 1 word long + +// next, the private data: + uint4 state[4]; + uint4 count[2]; // number of *bits*, mod 2^64 + uint1 buffer[64]; // input buffer + uint1 digest[16]; + uint1 finalized; + +// last, the private methods, mostly static: + void init (); // called by all constructors + void transform (uint1 *buffer); // does the real update work. Note + // that length is implied to be 64. + + static void encode (uint1 *dest, uint4 *src, uint4 length); + static void decode (uint4 *dest, uint1 *src, uint4 length); + static void memcpy (uint1 *dest, uint1 *src, uint4 length); + static void memset (uint1 *start, uint1 val, uint4 length); + + static inline uint4 rotate_left (uint4 x, uint4 n); + static inline uint4 F (uint4 x, uint4 y, uint4 z); + static inline uint4 G (uint4 x, uint4 y, uint4 z); + static inline uint4 H (uint4 x, uint4 y, uint4 z); + static inline uint4 I (uint4 x, uint4 y, uint4 z); + static inline void FF (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void GG (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void HH (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void II (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + +}; diff -urN xpdf-0.7a/xpdf/pdftops.cc.orig xpdf-0.7a/xpdf/pdftops.cc --- xpdf-0.7a/xpdf/pdftops.cc.orig Tue Feb 17 14:58:25 1998 +++ xpdf-0.7a/xpdf/pdftops.cc Sun May 17 13:52:15 1998 @@ -61,6 +61,7 @@ if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftops version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("pdftops", " []", argDesc); exit(1); } diff -urN xpdf-0.7a/xpdf/pdftotext.cc.orig xpdf-0.7a/xpdf/pdftotext.cc --- xpdf-0.7a/xpdf/pdftotext.cc.orig Tue Feb 17 14:58:25 1998 +++ xpdf-0.7a/xpdf/pdftotext.cc Sun May 17 13:52:51 1998 @@ -59,6 +59,7 @@ if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftotext version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("pdftotext", " []", argDesc); exit(1); } diff -urN xpdf-0.7a/xpdf/rc4.cc.orig xpdf-0.7a/xpdf/rc4.cc --- xpdf-0.7a/xpdf/rc4.cc.orig Thu Jan 1 10:00:00 1970 +++ xpdf-0.7a/xpdf/rc4.cc Sat Apr 4 19:19:22 1998 @@ -0,0 +1,70 @@ +/************************************************************************ + * * + * RC4 Encryption Algorithm * + * Copyright Peter Gutmann 1995-1996 * + * * + ************************************************************************/ + +/* Optimized RC4 code, from an unknown source ("and they knew not from whence + it had come...") */ + +#include "rc4.h" + +void +rc4ExpandKey( RC4KEY *rc4, unsigned char const *key, int keylen ) +{ + int x, keypos = 0; + rc4word sx, y = 0; + rc4word *state = &rc4->state[ 0 ]; + + rc4->x = rc4->y = 0; + + for( x = 0; x < 256; x++ ) + state[ x ] = x; + + for( x = 0; x < 256; x++ ) + { + sx = state[ x ]; + y += sx + key[ keypos ]; +#ifdef USE_LONG_RC4 + y &= 0xFF; +#endif /* USE_LONG_RC4 */ + state[ x ] = state[ y ]; + state[ y ] = sx; + + if( ++keypos == keylen ) + keypos = 0; + } + } + +void +rc4Crypt( RC4KEY *rc4, unsigned char *data, int len ) +{ + rc4word x = rc4->x, y = rc4->y; + rc4word sx, sy; + rc4word *state = &rc4->state[ 0 ]; + + while (len--) { + x++; +#ifdef USE_LONG_RC4 + x &= 0xFF; +#endif /* USE_LONG_RC4 */ + sx = state[ x ]; + y += sx; +#ifdef USE_LONG_RC4 + y &= 0xFF; +#endif /* USE_LONG_RC4 */ + sy = state[ y ]; + state[ y ] = sx; + state[ x ] = sy; + +#ifdef USE_LONG_RC4 + *data++ ^= state[ ( unsigned char ) ( sx+sy ) ]; +#else + *data++ ^= state[ ( sx+sy ) & 0xFF ]; +#endif /* USE_LONG_RC4 */ + } + + rc4->x = x; + rc4->y = y; +} diff -urN xpdf-0.7a/xpdf/rc4.h.orig xpdf-0.7a/xpdf/rc4.h --- xpdf-0.7a/xpdf/rc4.h.orig Thu Jan 1 10:00:00 1970 +++ xpdf-0.7a/xpdf/rc4.h Sat Apr 4 19:19:30 1998 @@ -0,0 +1,25 @@ +#include + +#if !defined(__RC4_H__) +#define __RC4_H__ +/* If the system can handle byte ops, we use those so we don't have to do a + lot of masking. Otherwise, we use machine-word-size ops which will be + faster on RISC machines */ + +#if UINT_MAX > 0xFFFFL /* System has 32-bit ints */ +#define USE_LONG_RC4 +typedef unsigned int rc4word; +#else +typedef unsigned char rc4word; +#endif /* UINT_MAX > 0xFFFFL */ + +/* The scheduled RC4 key */ + +typedef struct { + rc4word state[ 256 ]; + rc4word x, y; +} RC4KEY ; + +void rc4ExpandKey( RC4KEY *rc4, unsigned char const *key, int keylen ); +void rc4Crypt( RC4KEY *rc4, unsigned char *data, int len ); +#endif diff -urN xpdf-0.7a/xpdf/xpdf-ltk.h.orig xpdf-0.7a/xpdf/xpdf-ltk.h --- xpdf-0.7a/xpdf/xpdf-ltk.h.orig Thu Jan 1 10:00:00 1970 +++ xpdf-0.7a/xpdf/xpdf-ltk.h Sun May 17 13:55:48 1998 @@ -0,0 +1,241 @@ +// This file was generated by ltkbuild 0.7a + +LTKWindow *makeWindow(LTKApp *app) { + return new LTKWindow(app, gFalse, "xpdf", xpdfIcon, NULL, + new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, + new LTKBox(NULL, 2, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 1, + new LTKScrollingCanvas("canvas", 0, 100, 100, 32, 32) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 1, + new LTKScrollbar("vScrollbar", 0, gTrue, 0, 100, &scrollVertCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKScrollbar("hScrollbar", 0, gFalse, 0, 100, &scrollHorizCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKEmpty() + ) + ), + new LTKBox(NULL, 14, 1, 0, 0, 0, 0, ltkBorderNone, 1, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, dblLeftArrow_bits, dblLeftArrow_width, dblLeftArrow_height, ltkButtonClick, &prevTenPageCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, leftArrow_bits, leftArrow_width, leftArrow_height, ltkButtonClick, &prevPageCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, rightArrow_bits, rightArrow_width, rightArrow_height, ltkButtonClick, &nextPageCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, dblRightArrow_bits, dblRightArrow_width, dblRightArrow_height, ltkButtonClick, &nextTenPageCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", "Page") + ), + new LTKBox(NULL, 1, 1, 4, 4, 2, 2, ltkBorderSunken, 0, 0, + new LTKTextIn("pageNum", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", &pageNumCbk, NULL) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel("numPages", 0, ltkLabelMaxLength, 9, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, zoomIn_bits, zoomIn_width, zoomIn_height, ltkButtonClick, &zoomInCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, zoomOut_bits, zoomOut_width, zoomOut_height, ltkButtonClick, &zoomOutCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, find_bits, find_width, find_height, ltkButtonClick, &findCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, postscript_bits, postscript_width, postscript_height, ltkButtonClick, &postScriptCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, about_bits, about_width, about_height, ltkButtonClick, &aboutCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKLabel("link", 0, ltkLabelFixedWidth, 8, "-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*", NULL) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, "Quit", ltkButtonClick, &quitCbk) + ) + ) + ) + ); +} + +LTKMenu *makeMenu() { + return new LTKMenu("xpdf", 7, + new LTKMenuItem("Open...", "O", menuOpen, &menuCbk, NULL), + new LTKMenuItem("Save as...", NULL, menuSavePDF, &menuCbk, NULL), + new LTKMenuItem(NULL, NULL, 0, NULL, NULL), + new LTKMenuItem("Rotate left", NULL, menuRotateLeft, &menuCbk, NULL), + new LTKMenuItem("Rotate right", NULL, menuRotateRight, &menuCbk, NULL), + new LTKMenuItem(NULL, NULL, 0, NULL, NULL), + new LTKMenuItem("Quit", "Q", menuQuit, &menuCbk, NULL) + + ); +} + +LTKWindow *makePostScriptDialog(LTKApp *app) { + return new LTKWindow(app, gTrue, "xpdf: PostScript output", NULL, "ok", + new LTKBox(NULL, 1, 3, 0, 0, 0, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 4, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Pages:") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 0, 0, + new LTKTextIn("firstPage", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, "lastPage") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "to") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 0, 0, + new LTKTextIn("lastPage", 0, 6, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, "fileName") + ) + ), + new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "File:") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 0, + new LTKTextIn("fileName", 0, 32, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, NULL) + ) + ), + new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton("ok", 1, "Ok", ltkButtonClick, &psButtonCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKEmpty() + ), + new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &psButtonCbk) + ) + ) + ) + ); +} + +LTKWindow *makeOpenDialog(LTKApp *app) { + return new LTKWindow(app, gTrue, "xpdf: Open...", NULL, "open", + new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, + new LTKFileReq("fileReq", 0, openSelectCbk, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") + ), + new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, + new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton("open", 1, "Open", ltkButtonClick, &openButtonCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKEmpty() + ), + new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &openButtonCbk) + ) + ) + ) + ); +} + +LTKWindow *makeSaveDialog(LTKApp *app) { + return new LTKWindow(app, gTrue, "xpdf: Save as...", NULL, "save", + new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 1, 1, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, + new LTKFileReq("fileReq", 0, saveSelectCbk, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*") + ), + new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, + new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton("save", 1, "Save", ltkButtonClick, &saveButtonCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKEmpty() + ), + new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, "Cancel", ltkButtonClick, &saveButtonCbk) + ) + ) + ) + ); +} + +LTKWindow *makeFindWindow(LTKApp *app) { + return new LTKWindow(app, gFalse, "xpdf: Find", NULL, "find", + new LTKBox(NULL, 1, 3, 0, 0, 0, 0, ltkBorderNone, 1, 1, + new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 1, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Text:") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderSunken, 1, 0, + new LTKTextIn("text", 0, 32, "-*-courier-medium-r-normal-*-14-*-*-*-*-*-*-*", NULL, NULL) + ) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 1, + new LTKEmpty() + ), + new LTKBox(NULL, 3, 1, 0, 0, 8, 0, ltkBorderNone, 1, 0, + new LTKBox(NULL, 1, 1, 8, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton("find", 1, "Find", ltkButtonClick, &findButtonCbk) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKEmpty() + ), + new LTKBox(NULL, 1, 1, 2, 8, 2, 2, ltkBorderNone, 0, 0, + new LTKButton(NULL, 0, "Close", ltkButtonClick, &findButtonCbk) + ) + ) + ) + ); +} + +LTKWindow *makeAboutWindow(LTKApp *app) { + return new LTKWindow(app, gFalse, "About xpdf", NULL, "close", + new LTKBox(NULL, 1, 2, 0, 0, 0, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 1, 11, 2, 2, 2, 2, ltkBorderSunken, 0, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 0, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, "-*-times-bold-i-normal-*-24-*-*-*-*-*-*-*", "xpdf") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 12, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Version " xpdfVersion) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 0, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, xpdfCopyright) + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 12, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "derekn@aimnet.com") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Supports PDF version " pdfVersion ".") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 0, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "The PDF data structures, operators, and specification") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 12, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "are copyright 1995 Adobe Systems Inc.") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 0, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Mouse button 1: select text / follow link") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 0, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Mouse button 2: pan window") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 12, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "Mouse button 3: menu") + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 12, ltkBorderNone, 0, 0, + new LTKLabel(NULL, 0, ltkLabelStatic, 8, NULL, "http://www.aimnet.com/~derekn/xpdf/") + ) + ), + new LTKBox(NULL, 2, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 1, 0, + new LTKEmpty() + ), + new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, + new LTKButton("close", 0, "Close", ltkButtonClick, &closeAboutCbk) + ) + ) + ) + ); +} + diff -urN xpdf-0.7a/xpdf/xpdf.cc.orig xpdf-0.7a/xpdf/xpdf.cc --- xpdf-0.7a/xpdf/xpdf.cc.orig Tue Feb 17 14:58:26 1998 +++ xpdf-0.7a/xpdf/xpdf.cc Sun May 17 13:53:58 1998 @@ -313,6 +313,7 @@ if (!ok || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("xpdf", "[ []]", argDesc); ret = 1; goto done2; @@ -353,6 +354,7 @@ // print banner fprintf(errFile, "xpdf version %s\n", xpdfVersion); fprintf(errFile, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); // open PDF file defPSFileName = app->getStringResource("psFile", NULL);